8

我正在使用 FactoryGirl 和 Rspec 进行测试。如果模型为 nil,则模型在 init 之后设置一个外键。因此它使用另一个关联的数据。但是我该如何测试呢?通常我会使用工厂来创建这个对象,并为“self.user.main_address.country_id”使用 stub_chain。但是随着这个对象的创建,初始化之后会被调用。我没有机会打断它。

after_initialize do
  if self.country_id.nil?
    self.country_id = self.user.main_address.country_id || Country.first.id
  end
end

任何的想法?

4

3 回答 3

10

理想情况下,最好测试行为而不是实现。测试是否设置了外键,而不是测试是否调用了该方法。

虽然,如果你想在after_initialize这里测试回调是一种可行的方法。

obj = Model.allocate
obj.should_receive(:method_here)
obj.send(:initialize)

Allocate将对象放入内存但不调用initialize. 设置期望后,您可以调用初始化并捕获方法调用。

于 2012-04-24T20:36:55.017 回答
6

奥兰多的方法有效,这是我想补充的另一种方法。(使用新的 rspec 'expect' 语法)

expect_any_instance_of(Model).to receive(:method_here)
Model.new
于 2016-01-31T00:11:03.630 回答
0

另一种方法是重构代码以允许简单的单元测试。照原样,您的代码正在接近我在回调中放入多少代码的上限:

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 shoulda-callback-matchers来测试您的回调实际上是否按预期触发:

 it { is_expected.to callback(:init_country_id).before(:initialize) }
于 2019-07-23T02:22:55.753 回答