Ruby on rails 如何测试是否对ActiveRecord::Relation的每个元素调用了方法? 问题

Ruby on rails 如何测试是否对ActiveRecord::Relation的每个元素调用了方法? 问题,ruby-on-rails,activerecord,rspec,relation,Ruby On Rails,Activerecord,Rspec,Relation,我有一个函数,它通过一个关系进行排序,并对每个成员调用一个方法: def do_stuff count = 0 foo.bars.active.each do |bar| bar.stuff count += 1 end count end 注意:active是bar上返回关系而不是数组的范围 我的测试是这样的: describe :do_stuff do let(:foo) { FactoryGirl.create(:foo) } before

我有一个函数,它通过一个关系进行排序,并对每个成员调用一个方法:

def do_stuff
  count = 0
  foo.bars.active.each do |bar|
    bar.stuff
    count += 1
  end
  count
end
注意:
active
bar
上返回关系而不是数组的范围

我的测试是这样的:

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
before do
  foo.bars.each do |bar|
    bar.should_receive(:stuff)
  end
end
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
问题是我没有真正验证是否调用过
bar.stuff
。当我试图将
do_stuf
重构为以下内容时,我伤了自己:

def do_stuff
  foo.bars.active.count do |bar|
    bar.stuff
  end
end
尽管对ActiveRecord::Relation调用
count
不会执行块,但所有测试仍然通过:(我希望在我的规范中有一个
before
块,它可以执行以下操作:

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
before do
  foo.bars.each do |bar|
    bar.should_receive(:stuff)
  end
end
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
问题是上面返回的
与代码中实例化的实例不同

答复 我终于找到了答案。这是一个本该失败的规范,它不会让你担心你是否在迭代数组或关系:

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

富工厂:

FactoryGirl.define do
  data { random_string }

  trait :with_bar do
    after_build do |foo|
      foo.bars << FactoryGirl.create(:bar)
    end
  end
end
FactoryGirl.define do
数据{random_string}
特点:用_-bar做
建完后做|福|

foo.bar我会这样做:

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
before do
  foo.bars.each do |bar|
    bar.should_receive(:stuff)
  end
end
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.bar.count
次,我们可以假设ruby
count
方法工作正常。如果调用一次,它也将被调用
n
次。

此解决方案的问题是
bar
将返回一个关系而不是一个数组。因此,通过stubing
条形图
并返回
数组
您已经创建了一个即使代码被破坏也会通过的规范。我知道这一点,因为我做了同样的事情;)刚刚意识到我的问题与我正在处理的代码不匹配。在酒吧里应该有一个范围。很抱歉给你带来了困惑。我将更新这个问题。这并不重要,您可以
stub\u chain(:bar,:active)
返回数组。最后,您将得到一个元素迭代器。对关系调用
count
意味着它将使用
选择count*…
命中数据库并返回一个整数。块内的代码永远不会执行。对数组调用
count
将在元素上迭代,因此将执行块。我真的需要类似于
Bar.any\u实例的东西。应该接收(:stuff)
但它在我的设置中不起作用。