CapnKernul asks:
Hey Avdi. How would you test that a method’s provided block is called in RSpec? Would you stub #to_proc (for &block) and mock #call?
Typically the way I test that a block is called goes something like this:
describe ZeroWing do let(:probe) { lambda{} } context "given a signal handler" do subject.on_we_get_signal(&probe) it "triggers the handler when signaled" do probe.should_receive(:call) subject.we_get_signal! end end end
That’s for the simple case of just checking if the block is called. When I want to make assertions about the block arguments, I often switch to a style which records the yielded arguments and then makes assertions on them after the fact.
describe Array do subject { [1,2,3] } describe "#reverse_each" do it "yields the elements in backwards order" do yielded = [] subject.reverse_each do |e| yielded << e end yielded.should eq([3,2,1]) end end end
I don’t know if this is the best way, but it’s the way I usually do it.
I think
subject.on_we_get_signal(&probe)
needs to be in abefore(:each)
block–you can’t call it like that ddirectly in the “class body” of the example group.The mocking approach you’ve described here is interesting, I always use something closer to your second approach even for the simple case of just asserting the block was called:
it ‘calls the given block’ do
block_called = false
subject.method_that_calls_block { block_called = true }
block_called.should be_true
end
The mocking doesn’t gain anything over this approach IMHO, and it’s more fragile. If the method-under-test calls the block using #call, it’ll work fine, but what if it just uses a plain old
yield
?+1 for
block_called = true
What about something like
MockBlock
here: https://gist.github.com/1428875That doesn’t care whether the implementation actually uses
#call
oryield
, and shows a readable technique for testing the order of the calls. I find that a lot nicer to read than the oldblock_called.should be_true
oryielded.should ==
style.Nice!
Given the following code block:
barcode = Barby::Code128B.new(data)
File.open(“test.png”, ‘w’) do |f|
f.write barcode.to_png(height: 100, margin: 5)
end
How would I test that code within the block was executed? Specifically the calls to f.write or barcode.to_png?
You’d check to see if a file had been written to the filesystem!
Couldn’t you stub File.open to yield a mock file, then assert that the mock receives the write call?
The first rule of mocking is: Only mock what you own!
See http://www.virtuouscode.com/2013/04/22/rubytapas-freebie-the-end-of-mocking/ for more on why mocking out the filesystem is a bad idea.
The first example is just great! I really don’t like creating superfluous instance variables to validate things. By adding on a .with(foo) I can keep my tests completely out of the caller/consumer space. Thanks!