【问题标题】:Testing & Mocking Services with Rspec使用 Rspec 进行测试和模拟服务
【发布时间】:2013-07-01 11:31:54
【问题描述】:

我创建了一个名为 Transaction 的服务对象,它处理订单,设置付款,然后设置模型关联。

这个类被称为事务,有两个方法,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 模型使用了设计。设计测试助手不能在控制器之外使用,而且由于我在服务中进行测试,所以它不起作用。

【问题讨论】:

  • FactoryGirl 和 Devise 应该不是问题。服务测试应该类似于模型测试。您应该可以将 FactoryGirl 用于您的模型,不是吗?

标签: ruby-on-rails ruby testing rspec


【解决方案1】:

很难具体说明,因为您没有提供您的 Transaction 类代码,但总体而言,我建议您这样做:

  • 不要使用 FactoryGirl 或 Devise 助手 - 理想情况下,您正在为此类编写单元测试,因此您不需要任何外部依赖项。
  • 存根您正在处理的所有模型实例 - 这就是您使用 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

您会注意到我只需要事务文件 - 这有助于您了解它所依赖的其他类,因为您将(理想情况下)存根常量,或者在必要时需要其他文件。它也会使这个规范的运行时间更好。

另外,我只在帐户 double 上存根 confirmed?,而不是 confirmed。从 Rails 的角度来看,它们的含义相同,但最好始终使用其中之一,而不是同时使用两者。

如果您有大量设置(大量常量和测试替身),那么我认为这表明这个 Transaction 类可能需要分解成几个更具体的类。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-24
    • 2013-04-01
    • 2023-03-09
    • 2021-03-15
    • 2011-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多