Test if a block is passed with RSpec Mocks
Asked Answered
A

3

19

I can test if arguments are passed like:

RSpec.describe do
  it do
    obj = double
    expect(obj).to receive(:method).with(1, 2, 3)
    obj.method(1, 2, 3)
  end
end

How should I do about a block parameter? My ideal code:

RSpec.describe do
  it do
    obj = double
    proc = Proc.new{}
    expect(obj).to receive(:method).with(1, 2, 3).with_block(proc)
    obj.method(1, 2, 3, &proc)
  end
end
Armington answered 2/12, 2014 at 7:31 Comment(1)
Requested this feature on Rspec issues github.com/rspec/rspec-mocks/issues/1182Joost
A
13

It seems that I cannot simply test if a block is passed with method chaining. And I found one dull answer, Block Implementation:

RSpec.describe do
  it do
    obj = double
    proc = Proc.new{}
    expect(obj).to receive(:method).with(1, 2, 3) do |*args, &block|
      expect(proc).to be(block)
    end
    obj.method(1, 2, 3, &proc)
  end
end

However, we cannot use a block implementation and other response configuration methods at the same time like receive(:method).with(1, 2, 3){|*| ...}.and_call_original.

Armington answered 5/12, 2014 at 7:31 Comment(2)
I wonder if you might be able to simulate .and_call_original by using super(*args, &block) in the block implementation....Patric
RSpec should return the last statement in the do block:Toxin
S
3

Based on the git ticket above, you can do this via

expect(object)
  .to receive(:method)
  .with(param1, param2) do |&block|
    expect(block).to be('my block contents')
  end
  .and_call_original

Which will validate the parameters are passed and evaluate the block contents. You can then chain .and_mock_original or .and_call_original etc. afterwards.

Spiroid answered 11/5, 2018 at 21:37 Comment(0)
D
1

You cannot use expectation to test that a specific block is passed. You can check that a code is run by adding code inside it, for example:

RSpec.describe do
  it do
    obj = double
    block_is = double('block')
    block = -> {
      block_is.run
    }

    expect(obj).to receive(:method).with(1, 2, 3).and_yield
    expect(block_is).to receive(:run)

    obj.method(1, 2, 3, &block)
  end
end
Dree answered 2/12, 2014 at 7:57 Comment(1)
Hmm, I just have been able to use: allow(obj).to receive(:method).with(1, 2, 3, &a_proc).and_return(a_value). And it worked as expected.. EDIT: meh, rspec just ignored block )Carnes

© 2022 - 2024 — McMap. All rights reserved.