Edmund Lee Edmund Lee - 5 months ago 31
Ruby Question

Test if a method takes a block

How can I verify if

takes a block. Something simliar to

class Foobar
def some_method


This is useful for testing contract interface. Ensuring the method I stub has an unchanged API.

Ways I've tried

mth = Foobar.new.method(:some_method)

this returns a list of parameters (what Rspec uses essentially). It works if I have an argument as block like this:

def some_method(&blk)

But if a method uses
instead, I got nothing from

This is for adding specs for ensuring the interface with the ugly outside world. So I know how a method is used. But if there is an API change, I'd like specs to fail.

Answer Source

How can I verify if Foobar#some_method takes a block.

Every method in ruby takes (can take) a block. It may simply choose not to yield. So that's what you need to check, I think: if the method yielded or not.

RSpec has a number of yield expectations: https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/yield-matchers

RSpec.describe "yield_control matcher" do
  specify { expect { |b| MyClass.yield_once_with(1, &b) }.to yield_control }
  specify { expect { |b| MyClass.dont_yield(&b) }.not_to yield_control }
  specify { expect { |b| MyClass.yield_twice_with(1, &b) }.to yield_control.twice }
  specify { expect { |b| MyClass.yield_twice_with(1, &b) }.to yield_control.exactly(2).times }
  specify { expect { |b| MyClass.yield_twice_with(1, &b) }.to yield_control.at_least(1) }
  specify { expect { |b| MyClass.yield_twice_with(1, &b) }.to yield_control.at_most(3).times }


So for your case it should be something like this:

expect{ foobar.some_method }.to yield_control
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download