如何在 Rails 3 中存根 find_each 进行 rspec 测试

发布于 2024-10-06 16:48:08 字数 450 浏览 1 评论 0原文

我想知道如何在 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 测试?

I was wondering how to test a find_each call in rspec. I'm used to simply stubbing what I want my models to return so I don't rely on test data in the db like this:

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

However, in another class I'm doing this:

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

I find that if I do this:

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

in the spec test, the "do stuff here" part is not being executed. Does anyone know how to stub a find_each for rspec testing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

奶气 2024-10-13 16:48:08

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

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

You can use and_yield to make rspec call the block passed to the mock:

MyClass.stub(:find_each).and_yield(one_mock).and_yield(two_mock)
回忆躺在深渊里 2024-10-13 16:48:08

如果您需要在已验证的双精度上存根 find_each 并让它循环遍历特定的值数组,您可以这样做:

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

If you need to stub find_each on a verified double and have it loop through a specific array of values, you can do this:

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
箜明 2024-10-13 16:48:08

存根方法的全部目的是让该方法返回预期值而不执行其内容。如果 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

The whole point of stubbing a method is so that the method returns an expected value and not execute its contents. If you have a bunch of logic within the find_each method, I would recommend moving it to a separate method and testing that logic separately. You can then test that your method is called during execution.

Here's a pretty high level example:

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
不奢求什么 2024-10-13 16:48:08

这应该可以做到:

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

This should do it:

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

If do_stuff_here_on isn't globally reachable, e.g. an instance method on some_object, you'll need some instance_eval to get the right scope for the block:

MyClass.stub(:find_each) {|block|
  some_object.instance_eval(&block)
  [one_mock, two_mock]
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文