测试rspec中的多步骤工作流程

时间:2010-12-13 16:10:19

标签: ruby rspec bdd

我想知道使用rspec测试多步骤工作流程的习语或最佳实践。

我们以“购物车”系统为例,购买过程可能是

  1. 当用户提交购物篮并且我们未使用https时,重定向到https
  2. 当用户提交购物篮并且我们使用https并且没有cookie时,创建并显示新购物篮并发回cookie
  3. 当用户提交购物篮并且我们使用https并且有一个有效的cookie并且新商品用于与第一个商品不同的商品时,在购物篮中添加一行并显示两行
  4. 当用户提交购物篮并且我们使用https并且有一个有效的cookie并且新商品用于与前一个相同的产品时,增加该购物篮的数量并显示两行
  5. 当用户点击购物篮页面上的“结帐”并使用https并且有一个Cookie且该购物篮非空时...
  6. ...
  7. 我已经读过http://eggsonbread.com/2010/03/28/my-rspec-best-practices-and-tips/,它告诉ia每个“it block”应该只包含一个断言:而不是进行计算,然后在同一个块中测试几个属性,在上下文中使用“before”创建(或检索)测试对象并将其分配给@some_instance_variable,然后将每个属性测试写为单独的块。这有点帮助,但在如上所述的情况下,测试步骤n需要完成步骤[1..n-1]的所有设置,我发现自己要么重复设置代码(显然不好),要么创建大量辅助函数越来越笨拙的名字(def create_basket_with_three_lines_and_two_products)并在阻止之前的每个步骤中连续调用它们。

    关于如何做到这一点的任何提示都不那么冗长/繁琐?我理解这个想法背后的一般原则,即每个示例都不应该依赖前面示例留下的状态,但是当您测试多步骤过程并且在任何步骤都可能出错时,为每个步骤设置上下文是不可避免地要求重新运行前n个步骤的所有设置,所以......

2 个答案:

答案 0 :(得分:3)

这是一种可能的方法 - 定义一个对象,为每个步骤创建必要的状态,并为每个步骤传递它。基本上你需要模拟/存根所有设置条件的方法调用:

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 :(得分:1)

OP当然太迟了,但这对其他人来说可能很方便 - rspec-steps gem似乎是针对这种情况构建的:https://github.com/LRDesign/rspec-steps

同样值得看https://github.com/railsware/rspec-example_stepshttps://github.com/jimweirich/rspec-given也许是值得的。我选择了rspec-steps,但我很匆忙,其他选项可能实际上对我所知道的更好。