39

我想知道如何在 rspec 中测试 find_each 调用。我习惯于简单地将我希望我的模型返回的内容存根,所以我不依赖数据库中的测试数据,如下所示:

MyClass.stub(:find).and_return(my_mock)

但是,在另一堂课中,我正在这样做:

MyClass.find_each do |instance_of_my_class|
  do_stuff_here_on(instance_of_my_class)
end

我发现如果我这样做:

MyClass.stub(:find_each).and_return([one_mock, two_mock])

在规范测试中,“在这里做事”部分没有被执行。有谁知道如何存根 find_each 以进行 rspec 测试?

4

4 回答 4

53

您可以使用 and_yield 使 rspec 调用传递给模拟的块:

MyClass.stub(:find_each).and_yield(one_mock).and_yield(two_mock)
于 2010-12-08T07:15:11.190 回答
2

存根方法的全部意义在于使方法返回预期值而不执行其内容。如果您在 find_each 方法中有一堆逻辑,我建议将其移至单独的方法并单独测试该逻辑。然后,您可以测试您的方法在执行期间是否被调用。

这是一个非常高级的示例:

class Example1
  def my_method
    # some logic
  end
end

class Example2
  def my_other_method
    Example1.find_each(&:my_method)
  end
end

规格:

describe Example1 do
  it "should return something" do
    example = Example1.new
    example.my_method.should == something
  end
end

describe Example2 do
  it "should call my_method on Example1" do
    example1 = mock(:example1, :my_method => true)
    example2 = Example2.new

    example1.should_receive(:my_method)
    example2.my_other_method
  end
end
于 2010-12-08T02:15:39.243 回答
2

如果您需要find_each对已验证的 double 进行存根并让它遍历特定​​的值数组,您可以这样做:

let(:my_relation_with_mocked_find_each) do
  relation = instance_double('YourModel::ActiveRecord_Relation')

  receive_yield = receive(:find_each)

  fake_objs.each do |obj|
    receive_yield = receive_yield.and_yield(obj)
  end

  allow(relation).to receive_yield
  relation
end
于 2018-10-01T13:30:58.643 回答
1

这应该这样做:

MyClass.stub(:find_each) {|block|
  block.call
  [one_mock, two_mock]
}

如果do_stuff_here_on不能全局访问,例如some_object上的实例方法,您将需要一些 instance_eval 来获得块的正确范围:

MyClass.stub(:find_each) {|block|
  some_object.instance_eval(&block)
  [one_mock, two_mock]
}
于 2011-11-21T08:47:29.243 回答