使用多个“it”块在rspec中设置测试

时间:2011-09-03 16:09:09

标签: ruby-on-rails ruby rspec tdd bdd

假设我有一个实例方法可以完成我需要测试的许多不同的事情,例如store#process_order。我想测试它是否向客户发送了一封电子邮件,在订单表中添加了一个条目,收取了信用卡等等。在rspec中设置这个内容的最佳方法是什么?目前,我正在使用rspec和工厂女孩我做这样的事情:

describe Store do
  describe "#process_order" do
    before do
      @store = Factory(:store)
      @order = Factory(:order)
      # call the process method
      @store.process_order(@order)
    end

    it 'sends customer an email' do
      ...
    end
    it 'inserts order to db' do
      ...
    end
    it 'charges credit card' do
      ...
    end
  end
end

但感觉真的很乏味。这是否真的是为方法编写规范的正确方法,我需要确保做几件不同的事情?

注意:我对这是否是好设计的答案不感兴趣。这只是我用来解决问题的一个例子 - 如何编写这些类型的规范。

3 个答案:

答案 0 :(得分:2)

这是一个很好的方法,因为如果将来出现问题,您可以确定哪个元素被破坏了。我全都是为了单独测试。我倾向于不检查插入数据库的东西,因为你是rails功能。我只是检查对象的有效性。

这也是RSpec书中使用的方法。如果您不确定与RSpec有关的任何事情,我肯定会建议您阅读。

答案 1 :(得分:1)

我认为你所做的很好,我认为这是rspec的使用方式。关于您的应用的每个声明(规范)都有自己的块。

您可以考虑使用before (:all) do,这样订单只需要处理一次,但这可能会导致依赖于规范运行的顺序。

如果您愿意,可以将describe "#process_order"内的所有代码组合到一个大的it块中,但随后它会降低可读性,并且当规范失败时,rspec会为您提供较少的有用错误消息。前进并将raise添加到您的某个测试中,看看如果您按照当前的方式执行此操作,可以从rspec获得一条很好的错误消息。

答案 2 :(得分:1)

如果您想测试整个过程,那么我们讨论的是集成测试,而不是单元测试。如果你想测试做几件事的#process_order 方法,那么我希望那些东西意味着调用其他方法。所以,我会添加#should_receive期望,并确保涵盖所有路径。然后我会单独指定所有这些方法,所以我有一个很好的单位规格套件的一切。最后,我肯定会编写一个集成/验收规范,检查所有这些部分是否在一起工作。

另外,我会使用#let来设置测试对象,删除规范示例之间的依赖关系(它阻止)。否则,其中一个示例的失败可能会导致其他示例中的失败,从而给出错误的反馈。