我有一个ActiveRecord模型,PricePackage.有一个before_create回调.此回叫使用第三方API进行远程连接.我正在使用工厂的女孩,想要扼杀这个api,以便在测试过程中建立新的工厂时,不会产生远程调用.
我使用Rspec进行嘲弄和存根.我遇到的问题是Rspec方法在我的工厂.rb中不可用
模型:
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模拟和存根帮助器加载到我的工厂.这可能不是处理这个的最好方法.
解决方法
作为VCR宝石的作者,您可能希望我推荐这样的案例.我确实推荐它来测试与HTTP相关的代码,但我认为您的设计存在一个潜在的问题.不要忘记,TDD(测试驱动型开发)意在成为一种设计规范,当您发现轻松测试某件事情感到痛苦时,就会告诉您有关设计的内容.听你的测试痛!
在这种情况下,我认为您的模式没有业务进行第三方API呼叫.这是违反单一责任原则的重大违法行为.模型应该对某些数据的验证和持续性负责,但这绝对超出了这一点.
相反,我建议您将第三方API调用移动到观察者中.帕特·马多克斯(Pat Maddox)有一个great blog post讨论观察者如何(而且应该)将它们松散地耦合在一起,而不会违反SRP(单一责任原则),以及如何使测试更容易,并且还可以改善您的设计.
一旦将其移动到观察者中,就可以很容易地禁用单元测试中的观察者(除了该观察者的特定测试除外),但在生产和集成测试中保持启用.您可以使用Pat的no-peeping-toms插件来帮助您,或者如果您使用的是导轨3.1,则应该查看ActiveModel内置的new functionality,它允许您使用easily enable/disable observers.