我有一个通过Relation迭代的函数,并在每个成员上调用一个方法:
def do_stuff
count = 0
foo.bars.active.each do |bar|
bar.stuff
count += 1
end
count
end
注意:active
是bars
上的范围,它返回Relation而不是Array。
我的测试看起来像这样:
describe :do_stuff do
let(:foo) { FactoryGirl.create(:foo) }
before { foo.bars << FactoryGirl.create(:bar, :mock_stuff) }
subject { foo }
it { subject.do_stuff.should == 1 }
it "does lots of stuff" do
5.times { subject.bars << FactoryGirl.create(:bar, :mock_stuff) }
subject.do_stuff.should == 6
end
end
酒吧工厂
FactoryGirl.define do
data { random_string }
trait :mock_stuff do
after_build { |bar| bar.stub(:stuff).and_return(true) }
end
end
问题是我实际上并未验证bar.stuff
是否被调用过。当我试图重构do_stuff
时,我烧了自己:
def do_stuff
foo.bars.active.count do |bar|
bar.stuff
end
end
即使在ActiveRecord :: Relation上调用count
也不会执行块,所有测试仍然通过:(我想在我的规范中有一个before
块做某事像这样:
before do
foo.bars.each do |bar|
bar.should_receive(:stuff)
end
end
问题是上面返回的bar
将是与代码中实例化的实例不同的实例。
我终于明白了。这是规范失败的时候应该而且不会让你担心你是在迭代数组还是关系:
describe :do_stuff do
subject { FactoryGirl.create(:foo, :with_bar) }
it "does stuff to bar" do
Bar.any_instance.should_receive(:stuff)
subject.do_stuff
end
end
这里的诀窍是你不能在let
块中定义foo,就像我在第一个例子中所做的那样。
The Foo Factory:
FactoryGirl.define do
data { random_string }
trait :with_bar do
after_build do |foo|
foo.bars << FactoryGirl.create(:bar)
end
end
end
现在,当我做一些像foo.bars.active.count do |bar|
这样愚蠢的事情时,我的规范失败了,我知道代码已经坏了。
答案 0 :(得分:0)
我会做这样的事情:
let(:foo) { FactoryGirl.create(:foo) }
let(:bar) { double }
let(:array) { [bar] }
before do
foo.stub(:bars).and_return(array)
end
it 'calls stuff on bar' do
expect(bar).to receive(:stuff).once
foo.do_stuff
end
您实际上不需要确保它将被调用foo.bars.count
次,我们可以假设ruby count
方法正常工作。如果它被调用一次,它也将被称为n
次。