1

如何使用RSpec来验证方法是否接收到特定块?考虑这个简化的例子:

class MyTest
  def self.apply_all_blocks(collection, target)
    collection.blocks.each do |block|
      target.use_block(&block)
    end
  end
end

我想要一个规范来验证target.use_block每个由collection.blocks.

以下代码不起作用:

describe "MyTest" do
  describe ".apply_all_blocks" do
    it "applies each block in the collection" do
      target = double(Object)
      target.stub(:use_block)

      collection = double(Object)
      collection.stub(:blocks).and_return([:a, :b, :c])

      target.should_receive(:use_block).with(:a)
      target.should_receive(:use_block).with(:b)
      target.should_receive(:use_block).with(:c)

      MyTest.apply_all_blocks(collection, target)
    end
  end
end

(另外,use_block不一定调用块,因此测试块接收到是不够的call。同样,我不认为target.should_receive(:use_block).and_yield会做我想做的事。)

4

2 回答 2

3

如果您创建 lambdas 而不是符号,它将按预期工作:

describe "MyTest" do
  describe ".apply_all_blocks" do
    let(:a) { lambda {} }
    let(:b) { lambda {} }
    let(:c) { lambda {} }
    it "applies each block in the collection" do
      target = double(Object)
      target.stub(:use_block)

      collection = double(Object)
      collection.stub(:blocks).and_return([a, b, c])

      target.should_receive(:use_block).with(&a)
      target.should_receive(:use_block).with(&b)
      target.should_receive(:use_block).with(&c)

      MyTest.apply_all_blocks(collection, target)
    end
  end
end

注意:我将类名从 更改为TestMyTest以便它实际运行;Test将与真正的Test班级发生冲突。我也修改了您的问题,以便它可以剪切和粘贴运行。

于 2013-05-28T14:26:34.557 回答
1

我知道这是一个老问题,但目前接受的答案是不正确的。

验证接收到特定块的正确方法是将验证块传递给should_receive专门将接收到的块与您期望接收的块进行比较的块:

在 RSpec 2.13(原始问题时的当前版本)中:

a = lambda {}
target.should_receive(:use_block) do |&block|
  expect(block).to eq(a)
end

在 RSpec 3.4 中(撰写本文时的当前版本):

a = lambda {}
expect(target).to receive(:use_block) do |&block|
  expect(block).to eq(a)
end

将块传递给with另一个答案中的建议不足以验证块是否被实际接收,因为 rspec 使用该块来设置返回值,而不是与方法实际接收的块进行比较。

请参阅有关将块传递receive.

另请参阅最近关于 RSpec 邮件列表的讨论

于 2016-02-19T16:30:29.960 回答