тестирование многошагового рабочего процесса в rspec - PullRequest
7 голосов
/ 13 декабря 2010

Я хотел бы узнать об идиомах или передовых методах тестирования многошагового рабочего процесса с использованием rspec.

Давайте возьмем в качестве примера систему «корзины покупок», где процесс покупки может быть

  1. , когда пользователь отправляет заявку в корзину, а мы не используем https, перенаправить на https
  2. когда пользователь отправляет заявку в корзину, а мы используем https, а файл cookie отсутствует, создайте и отобразите новую корзину и отправьте обратно cookie
  3. , когда пользователь отправит заявку в корзину, а мы используем https идействительный файл cookie, и новый элемент предназначен для продукта, отличного от первого элемента, добавьте строку в корзину и отобразите обе строки
  4. , когда пользователь отправляет заявку в корзину, а мы используем https и существует действительный файл cookie иновый товар предназначен для того же продукта, что и предыдущий, увеличивайте количество строк этой корзины и отображайте обе строки
  5. , когда пользователь нажимает кнопку «оформить заказ» на странице корзины и использует https, а также имеется файл cookie и корзинане является пустым и ...
  6. ...

Я прочитал http://eggsonbread.com/2010/03/28/my-rspec-best-practices-and-tips/, который советует, что каждый «it блок» должен содержать толькоy одно утверждение: вместо того, чтобы выполнять вычисления и затем тестировать несколько атрибутов в одном и том же блоке, используйте «до» внутри контекста, чтобы создать (или получить) тестируемый объект и назначить его @some_instance_variable, а затем записать каждый тест атрибута какотдельный блок.Это немного помогает, но в случае, подобном описанному выше, где этап n тестирования требует выполнения всей настройки для шагов [1..n-1], я обнаруживаю, что либо дублирую код установки (очевидно, не очень хороший), либо создаю множество вспомогательных функций.со все более громоздкими именами (def create_basket_with_three_lines_and_two_products) и последовательным их вызовом в каждом шаге перед блоком before.

Какие-нибудь советы о том, как сделать это менее многословно / утомительно?Я ценю общий принцип, лежащий в основе идеи о том, что каждый пример не должен зависеть от состояния, оставленного предыдущими примерами, но когда вы тестируете многоэтапный процесс, и на любом этапе все может пойти не так, настройка контекста для каждого шаганеизбежно потребуется перезапустить все настройки для предыдущих n шагов, так что ...

Ответы [ 2 ]

3 голосов
/ 14 декабря 2010

Вот один из возможных подходов - определить объект, который создает необходимое состояние для каждого шага, и передать его вперед для каждого последующего. В основном вам нужно смоделировать / заглушить вызовы метода для всех условий настройки:

class MultiStep
  def initialize(context)
    @context = context
  end

  def init_vars
    @cut = @context.instance_variable_get(:@cut)
  end

  def setup(step)
    init_vars
    method(step).call
  end

  def step1
    @cut.stub(:foo).and_return("bar")
  end

  def step2
    step1
    @cut.stub(:foo_bar).and_return("baz_baz")
  end
end

class Cut  # Class Under Test
  def foo
    "foo"
  end
  def foo_bar
    "foo_bar"
  end
end

describe "multiple steps" do
  before(:each) do
    @multi_stepper = MultiStep.new(self)
    @cut = Cut.new
  end

  it "should setup step1" do
    @multi_stepper.setup(:step1)
    @cut.foo.should == "bar"
    @cut.foo_bar.should == "foo_bar"
  end

  it "should setup step2" do
    @multi_stepper.setup(:step2)
    @cut.foo.should == "bar"
    @cut.foo_bar.should == "baz_baz"
  end

end
1 голос
/ 27 марта 2013

Конечно, слишком поздно для OP, но это может быть удобно для других - кажется, что гем rspec-steps создан именно для этой ситуации: https://github.com/LRDesign/rspec-steps

Возможно, стоит взглянуть на https://github.com/railsware/rspec-example_steps и https://github.com/jimweirich/rspec-given.Я остановился на rspec-steps, но спешил, и эти другие варианты могли бы быть лучше для всех, что я знаю.

...