如何在rails 3中将find_each存根到rspec测试中

时间:2010-12-07 23:18:12

标签: ruby-on-rails rspec rspec2

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

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])

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

4 个答案:

答案 0 :(得分:42)

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

MyClass.stub(:find_each).and_yield(one_mock).and_yield(two_mock)

答案 1 :(得分: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

Rspec的:

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

答案 2 :(得分: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]
}

答案 3 :(得分:0)

如果您需要将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