我有一个 ActiveRecord 模型 PricePackage。那有一个 before_create 回调。此回调使用第 3 方 API 进行远程连接。我正在使用工厂女孩,并且想删除这个 api,以便在测试期间建立新工厂时不会进行远程调用。
我将 Rspec 用于模拟和 stub 。我遇到的问题是我的 factory.rb 中没有 Rspec 方法
模型:
class PricePackage < ActiveRecord::Base
has_many :users
before_create :register_with_3rdparty
attr_accessible :price, :price_in_dollars, :price_in_cents, :title
def register_with_3rdparty
return true if self.price.nil?
begin
3rdPartyClass::Plan.create(
:amount => self.price_in_cents,
:interval => 'month',
:name => "#{::Rails.env} Item #{self.title}",
:currency => 'usd',
:id => self.title)
rescue Exception => ex
puts "stripe exception #{self.title} #{ex}, using existing price"
plan = 3rdPartyClass::Plan.retrieve(self.title)
self.price_in_cents = plan.amount
return true
end
end
工厂:
#PricePackage
Factory.define :price_package do |f|
f.title "test_package"
f.price_in_cents "500"
f.max_domains "20"
f.max_users "4"
f.max_apps "10"
f.after_build do |pp|
#
#heres where would like to mock out the 3rd party response
#
3rd_party = mock()
3rd_party.stub!(:amount).price_in_cents
3rdPartyClass::Plan.stub!(:create).and_return(3rd_party)
end
end
我不确定如何将 rspec 模拟和 stub 助手加载到我的 factory.rb 中,这可能不是处理此问题的最佳方法。
最佳答案
作为 VCR gem 的作者,您可能希望我在此类情况下推荐它。我确实推荐它来测试依赖于 HTTP 的代码,但我认为您的设计存在潜在问题。不要忘记,TDD(测试驱动开发)是一门设计学科,当您发现轻松测试某些东西很痛苦时,这就是在告诉您有关您的设计的一些信息。听听你的测试的痛苦!
在这种情况下,我认为您的模型没有进行 3rd 方 API 调用的业务。这是对单一责任原则的严重违反。模型应该负责某些数据的验证和持久性,但这绝对不止于此。
相反,我建议您将第 3 方 API 调用移至观察者。 Pat Maddox 有一个 great blog post讨论如何使用观察者(并且应该)在不违反 SRP(单一责任原则)的情况下松散耦合事物,以及如何使测试变得更加容易,并改善您的设计。
将其移入观察者后,在单元测试中禁用观察者就很容易了(该观察者的特定测试除外),但在生产和集成测试中保持启用。您可以使用 Pat 的 no-peeping-toms插件来帮助解决这个问题,或者,如果您使用的是 rails 3.1,您应该查看 new functionality内置于 ActiveModel 中,允许您 easily enable/disable observers .
关于ruby-on-rails-3 - 如何使用 factory_girl 模拟和 stub 事件记录 before_create 回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7543782/