On 7 June 2010 15:25, Matt W. [email protected] wrote:
Have you seen and_yield? I can’t quite get my head around what you’re
trying
to do, but it might help anyway
Thank you, I have. My understanding is that #and_yield has much the same
use
as #and_return (in its non-bastardized-by-me-form). That is, you specify
it
in order to make the mocked-out collaborator behave enough like the real
collaborator that the object-under-test can work properly.
I’ll try to explain what I’m aiming for more comprehensibly.
If I my object-under-test calls a method with a parameter, I can make
assertions against the values passed. The simplest is equality:
foo.should_receive(:bar).with(6)
The corresponding code in the object-under-test is
foo.bar(6)
and the real code for the collaborator is something like:
class Foo
def bar(x)
// …
end
end
Now the collaborator in my case doesn’t take a parameter, it takes a
block:
class Foo2
def bar2(&block)
// …
end
end
and the object-under-test passes in a block which is called later for
its
return value:
foo2.bar2 { 6 }
(The real block doesn’t return a constant, obviously. It returns
something
which needs to be evaluated lazily because its dependencies don’t exist
yet.)
I want to test that the block passed in is the block that I expect.
Something like (in an imaginary world):
foo2.should_receive(:foo2).with(block(yielding(6)))
(In fact, in my case I can’t just assert equality on the return value
from
the block. I’m actually going to test its type.)
The corresponding test using my obscene #and_return hack looks like
this:
foo2.should_receive(:foo2).and_return { |block| block.call.should ==6
}
But this doesn’t scale to multiple calls to #foo2 in the object under
test
because RSpec (understandably) matches its expectations against
invocations
based on method name and argument matchers.
-Ben