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

发布于 2024-12-02 16:42:42 字数 675 浏览 3 评论 0原文

假设我有一个实例方法,它可以执行许多需要测试的不同操作,例如 store#process_order。我想测试它是否向客户发送电子邮件、在订单表中添加条目、向信用卡收费等。在 rspec 中设置此功能的最佳方法是什么?目前,我正在使用 rspec 和 Factory Girl,我做了这样的事情:

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

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

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

Say I have an instance method that does many different things that I need to test, something like store#process_order. I'd like to test that it sends an email to the customer, adds an entry in the orders table, charges a credit card, etc. What's the best way to set this up in rspec? Currently, I'm using rspec and factory girl I do something like this:

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

But it feels really tedious. Is this really the right way to write a spec for a method that I need to make sure does several different things?

Note: I'm not interested in answers about whether or not this is good design. It's just an example I made up to help w/ my question - how to write these types of specs.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

薔薇婲 2024-12-09 16:42:42

这是一个很好的方法,因为如果将来出现问题,您可以识别哪个元素被破坏。我完全赞成单独测试。我倾向于不检查插入到数据库中的内容,因为您当时是 Rails 功能。我只是简单地检查对象的有效性。

RSpec 书中也使用了这种方法。如果您不确定与 RSpec 相关的任何内容,我当然建议您阅读它。

This is a good method because you can identify which element is broken if something breaks in the future. I am all for testing things individually. I tend not to check things get inserted into the database as you are then rails functionality. I simply check the validity of the object instead.

This is the method that is used in the RSpec book too. I would certainly recommend reading it if you are unsure about anything related to RSpec.

缱倦旧时光 2024-12-09 16:42:42

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

您可能会考虑使用 before (:all) do ,以便订单只需处理一次,但这可能会引入对规范运行顺序的依赖性。

如果您愿意,您可以将 describe "#process_order" 中的所有代码合并到一个大的 it 块中,但这样可读性会较差,而且 rspec 也会给您带来不那么有用的结果规范失败时的错误消息。继续将 raise 添加到您的一个测试中,看看如果您按照当前的方式进行操作,可以从 rspec 中得到一条多么好的错误消息。

I think what you are doing is fine and I think it's the way rspec is intended to be used. Every statement (specification) about your app gets its own block.

You might consider using before (:all) do so that the order only has to get processed once but this can introduce dependencies on the order the specs are run.

You could combine all the code inside describe "#process_order" into one big it block if you wanted to, but then it would be less readable and rspec would give you less useful error messages when a spec fails. Go head and add raise to one of your tests and see what a nice error message you can get from rspec if you do it the way you are currently doing it.

夜无邪 2024-12-09 16:42:42

如果您想测试整个过程,那么我们讨论的是集成测试,而不是单元测试。如果您想测试执行多项操作的#process_order 方法,那么我希望这些操作意味着调用其他方法。因此,我会添加 #should_receive 期望并确保覆盖所有路径。然后我会分别规范所有这些方法,这样我就有了一个适合所有内容的很好的单元规范套件。最后,我肯定会编写一个集成/验收规范来检查所有这些部分是否一起工作。

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

If you want to test the entire process then we're talking about an integration test, not a unit test. If you want to test #process_order method which does several things, then I'd expect those things mean calling other methods. So, I would add #should_receive expectations and make sure that all paths are covered. Then I would spec all those methods separately so I have a nice unit spec suite for everything. In the end I would definitely write an integration/acceptance spec which checks if all those pieces are working together.

Also, I would use #let to setup test objects which removes dependencies between spec examples (it blocks). Otherwise a failure of one of the examples may cause a failure in other example giving you an incorrect feedback.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文