Verify that a method receives a particular block

43 views
Skip to first unread message

Nathan Wenneker

unread,
Feb 18, 2016, 5:47:45 PM2/18/16
to rspec
I want to verify that this method passes a block to a collaborator:


module Bar
 
def self.baz_wrapper(&block)
   
Foo.baz(&block)
 
end
end

Something like this would be nice:

it "passes the given block to Foo" do
  my_block
= lambda {}

  expect
(Foo).to receive(:baz).with(&my_block)

 
Bar.baz_wrapper(&my_block)
end

However, the best I could come up with is this:


it "passes the given block to Foo" do
  my_block
= lambda {}

  expect
(Foo).to receive(:baz) do |&block|
    expect
(block).to eq(my_block)
 
end

 
Bar.baz_wrapper(&my_block)
end

Questions.

1. Is there a better way to do this?

2. If not, would you be open to a discussion on making `expect(Foo).to receive(:baz).with(&my_block)` work?


Thank you,

Nathan



Jon Rowe

unread,
Feb 18, 2016, 6:13:47 PM2/18/16
to rs...@googlegroups.com
The problem with block arguments is there priority with Ruby… Consider that this:

it “returns my value" do
  expect
(Foo).to receive(:baz) { “my return value” }
end

Needs to return the same as this:

it “still returns my value" do
  expect
(Foo).to receive(:baz).with(:my_argument) { “my return value” }
end

And that is the same as this:

it “still returns my value” do
  my_block = lambda “my return value” }
  expect(Foo).to receive(:baz).with(:my_argument,&my_block)
end

And hopefully you can see why it doesn’t (and intend can’t) work the way you want it currently…

I’d be open to adding another way to match this however, maybe an argument matcher? 

it "passes the given block to Foo" do
  my_block 
= lambda {}

  # pseudo code, won’t work atm
  expect(Foo).to receive(:baz).with(block_argument(my_block))

  
Bar.baz_wrapper(&my_block)
end

Jon Rowe
---------------------------

--
You received this message because you are subscribed to the Google Groups "rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rspec+un...@googlegroups.com.
To post to this group, send email to rs...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/3bfa0a8a-4f55-4e24-8527-3f2f4eb693ea%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Myron Marston

unread,
Feb 18, 2016, 6:28:20 PM2/18/16
to rs...@googlegroups.com

As Jon pointed out, the rspec-mocks API allows you to use blocks to specify implementation logic and/or return values so I don’t think that making it also match on the block will work well. The solution you came up with looks OK to me. You could shorten it further with a helper method:

module ReceiveWithBlock
  def receive_with_block(method_name, &expected_block)
    receive(method_name) { |&block| expect(block).to eq expected_block }
  end
end

RSpec.configure do |config|
  config.include ReceiveWithBlock
end

Which you could then use with:

expect(Foo).to receive_with_block(:baz, &my_block)

Given the rarity of this need and that there are solutions, I would lean against adding anything additional to the RSpec API for it.

Myron



Nathan Wenneker

unread,
Feb 18, 2016, 7:03:07 PM2/18/16
to rs...@googlegroups.com
Jon and Myron,

Thanks both for your replies, and for pointing out my proposed API would be incompatible with the current API, since the block argument to `with` is already being used for something else. 

Jon's idea of `with(block_argument(my_block))` or perhaps a new constraint like `with_block(&my_block)` would be fine.

Of course I'll defer to your judgment about whether it's something you want in rspec-mocks proper or not.  If not, using a helper as Myron suggested is fine too.

I posted a more complex question/API proposal regarding testing that code is called from within a block a few days ago and haven't seen any replies yet. Since you both graciously responded to this question so quickly, I'm wondering if perhaps my post a few days ago slipped through the cracks due to it being a reply to an older post.

If you have time, please take a look here: https://groups.google.com/forum/#!topic/rspec/NL_NKukH6jQ

Thanks,

Nathan
Reply all
Reply to author
Forward
0 new messages