简体   繁体   English

使用Rspec进行测试和模拟服务

[英]Testing & Mocking Services with Rspec

I created a Service Object called Transaction which processes an order made, sets up the payments and then sets up a model association. 我创建了一个名为Transaction的服务对象,它处理订单,设置付款,然后建立模型关联。

The class is called Transaction with two methods, initialize and pay . 该类称为Transaction,有两种方法, initializepay I am testing it in spec/services/ (it is in app/services ). 我在spec/services/测试它(它在app/services )。

The initialize method takes in an account and some parameters passed in by the user to process the order. initialize方法接受一个account和一些用户传入的参数来处理订单。

I am trying to test pay with rspec. 我正试图用rspec测试pay How do I actually do such a test? 我该如何进行这样的测试? This function has a lot going on. 这个功能有很多功能。 For example, it creates new models, and then sets up some associations between them. 例如,它创建新模型,然后在它们之间建立一些关联。

So far, I created a double account as follows: 到目前为止,我创建了一个双重account ,如下所示:

@account = double("account", :confirmed => true, :confirmed? => true)

However, there are many functions (and associations) used in the Transaction pay method. 但是,交易支付方法中使用了许多功能(和关联)。 So for example when these associations are called (once I call Transaction.pay in the test), it returns an error: 例如,当调用这些关联时(一旦我在测试中调用Transaction.pay ),它就会返回一个错误:

ActiveRecord::AssociationTypeMismatch:
Business(#70250016824700) expected, got RSpec::Mocks:.

The business model is a double just like account , and added as an attribute to @account . business模型是一个双倍的account ,并作为属性添加到@account How can I test my Transaction.pay when it creates new models and associations in there? 如何在其中创建新模型和关联时测试我的Transaction.pay?

Do I need to mock all of them as shown above? 如上所示,我是否需要模拟所有这些? Or is there a better way to do it? 或者有更好的方法吗?

I am using FactoryGirl, but I am unable to use it as my account model uses Devise. 我正在使用FactoryGirl,但我无法使用它,因为我的account模型使用Devise。 Devise test helpers cannot be used outside of controllers, and since I'm testing in services, it won't work. 设计测试助手不能在控制器之外使用,因为我在服务中测试,它将无法工作。

It's hard to be specific, since you've not provided your Transaction class code, but at a high level, here's what I'd recommend: 很难具体,因为你没有提供你的Transaction类代码,但是在高级别,这是我推荐的:

  • Do not use FactoryGirl or Devise helpers - ideally, you're writing a unit test for this class, so you don't want any external dependencies. 不要使用FactoryGirl或Devise帮助程序 - 理想情况下,您正在为此类编写单元测试,因此您不需要任何外部依赖项。
  • Stub out any model instances you're dealing with - which is what you've done with account . 找出你正在处理的任何模型实例 - 这是你用account做的。
  • Stub out any external classes being used within the service (such as Business ), and if you're creating instances of those from the classes, then they're doubles too. 存根在服务中使用的任何外部类(例如Business ),如果您正在创建类的实例,那么它们也是双倍的。

Here's a vague example with no real implementation: 这是一个模糊的例子,没有真正的实现:

require './app/services/transaction'

describe Transaction do
  let(:transaction) { Transaction.new account, :foo => 'bar' }
  let(:account)     { double 'Account', :confirmed? => true }
  let(:business)    { double 'Business', :save => true }

  before :each do
    stub_const 'Business', double(:new => business)
  end

  describe '#pay' do
    it "does stuff" do
      # ...

      transaction.pay

      # ...
    end
  end
end

You'll note I've only required the transaction file - this helps you be aware of what other classes it depends on, because you'll (ideally) stub the constants, or if necessary, require other files. 你会注意到我只需要事务文件 - 这有助于你了解它依赖的其他类,因为你(理想情况下)存根常量,或者如果需要,需要其他文件。 It'll keep this spec's running time much better too. 它也会使这个规格的运行时间更好。

Also, I only stubbed confirmed? 还有,我只是confirmed? , not confirmed on the account double. ,未在账户上confirmed双倍。 From a Rails perspective they mean the same thing, but it's better to use one of them consistently, instead of both. 从Rails的角度来看,它们的意思相同,但最好始终如一地使用其中一个,而不是两者。

If you have a ton of setup (a lot of constants and test doubles), then I'd take that as a sign that this Transaction class probably needs to be broken up into several more specific classes. 如果你有大量的设置(很多常量和测试双打),那么我会把它作为这个Transaction类可能需要分解成几个更具体的类的标志。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM