我使用FactoryGirl和Rspec进行测试。如果init为nil,则模型在init后设置一个外键。因此,它使用另一种关联的数据。但是我如何测试它呢?通常我会使用工厂来创建这个对象,并使用stub_chain来"self.user.main_address.country_id"。但是随着这个对象的创建,initialize之后会被调用。我没机会把它拔掉了。
after_initialize do
if self.country_id.nil?
self.country_id = self.user.main_address.country_id || Country.first.id
end
end
任何想法?
理想情况下,最好测试行为而不是实现。测试是否设置了外键,而不是测试是否调用了方法。
但是,如果你想测试after_initialize
回调,这里有一种方法可以工作。
obj = Model.allocate
obj.should_receive(:method_here)
obj.send(:initialize)
Allocate将对象放入内存,但不调用initialize
。设置期望之后,就可以调用initialize并捕获方法调用。
Orlando的方法有效,这里是另一个我想添加的(使用新的rspec 'expect'语法)
expect_any_instance_of(Model).to receive(:method_here)
Model.new
另一种方法是重构代码以允许进行简单的单元测试。实际上,您的代码正在接近我在回调中放入的代码的上限:
after_initialize do
if self.country_id.nil?
self.country_id = self.user.main_address.country_id || Country.first.id
end
end
如果它增长得更多,我将把它提取到一个方法中,并将你的回调减少到一个方法调用:
after_initialize :init_country_id
def init_country_id
if self.country_id.nil?
self.country_id = self.user.main_address.country_id || Country.first.id
end
end
这里的好处是测试init_country_id
在这一点上变成了另一个方法单元测试…没什么特别的。
after_initialize :init_country_id
这样简单的东西不需要调用测试,IMO)
你可以使用gem should -callback-matchers来测试你的回调是否按预期被触发:
it { is_expected.to callback(:init_country_id).before(:initialize) }