如何测试一个rails模型的after_initialize回调



我使用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) }

相关内容

  • 没有找到相关文章

最新更新