2013-07-01 163 views
5

我创建了一个名为Transaction的服务对象,它处理订单,设置付款并设置模型关联。使用Rspec测试和嘲笑服务

该类被称为交易有两种方法,initializepay。我正在测试它在spec/services/(它在app/services)。

initialize方法需要account和用户传入的一些参数来处理订单。

我想用rspec测试pay。我怎样才能真正做这样的测试?这个功能有很多。例如,它会创建新模型,然后在它们之间建立一些关联。

到目前为止,我创建了一个双account如下:

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

不过,也有在交易付费方式使用的许多功能(和关联)。因此,例如,当这些关联(调用一次我打电话Transaction.pay测试),它返回一个错误:

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

business模型是一个双重就像account,并添加为@account属性。如何在创建新模型和关联时测试Transaction.pay?

我是否需要如上所示模拟它们全部?还是有更好的方法来做到这一点?

我正在使用FactoryGirl,但我无法使用它,因为我的account模型使用Devise。设计测试助手不能在控制器之外使用,并且由于我正在测试服务,所以它不起作用。

+0

FactoryGirl和Devise应该不成问题。服务测试应该与模型测试类似。你应该可以为你的模型使用FactoryGirl,不是吗? – phoet

回答

7

很难具体,因为你没有提供您的交易类的代码,但在较高的水平,这里是我建议:

  • 不要使用FactoryGirl或设计助手 - 理想,你正在为这个类编写一个单元测试,所以你不需要任何外部依赖。
  • 将您正在处理的任何模型实例都删除 - 这是您使用account完成的操作。
  • 将服务中正在使用的任何外部类(如Business)分开,并且如果要从类中创建实例,那么它们也是双倍的。

这里有没有真正实现一个模糊的例子:

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 

你会注意到,我只需要在交易文件 - 这可以帮助你了解它取决于什么其他类的,因为你(理想情况下)存根常量,或者必要时需要其他文件。它也会保持这个规格的运行时间。

另外,我只凿了confirmed?,而不是confirmed上的帐户加倍。从Rails的角度来看,它们意味着同样的东西,但最好是一致地使用其中之一,而不是两者。

如果你有大量的设置(很多常量和测试双打),那么我会认为这个事务类可能需要分解成几个更具体的类。