On 19 Mar 2011, at 13:35, David Chelimsky wrote:
> On Mar 18, 2011, at 10:37 AM, Srushti Ambekallu wrote:
>
>> Hey all,
>>
>> I would like to be able to be able to have mocks where I can make all the
>> calls and assert that it was called afterwards. This would be especially
>> useful when asserting on a doing-method whose return value is not being
>> considered.
>> e.g.
>> service = mock(ExternalService)
>> ExternalService.stub!(:new).and_return(service)
>> user = User.new
>> user.activate
>> service.should_have_received(:publish_user_activation).with(user)
>> Now this obviously can't replace all assertions done with should_receive,
>> but I know there are at least a few cases where this would come in handy and
>> be more readable. I know while writing tests, I usually write the actual
>> call (in this case the 'post') and then go up a couple of lines to write the
>> should_receive. I think it would be more natural to verify it after the fact
>> rather than before. I seem to remember there was another mocking library
>> which did something quite close to this, but I just can't seem to find it
>> just now. What does everyone think? I could try and implement this myself,
>> but just wanted to see if there was any interest, or any one had a good
>> reason not to include this.
>
> This pattern is called a test spy, and there has been much discussion of it
> on this list:
>
> http://groups.google.com/group/rspec/search?group=rspec&q=test+spies&qt_g=Search+this+group
>
> The biggest issue for me is that message expectations often get set with a
> stub return value:
>
> foo.should_receive(:bar).and_return(:baz)
> foo(:bar)
>
> In a world of test spies, this would be:
>
> foo.stub(:bar).and_return(:baz)
> foo(:bar)
> foo.should_have_received(:bar).with(:bam)
>
> This requires more code in the example, and creates an otherwise unnecessary
> binding between the stub and the expectation. Also, note that the stub
> doesn't constrain the argument to bar(), but should_have_received() does (in
> this example). If we were to do that the other way:
>
> foo.stub(:bar).with(:baz).and_return(:bam)
> bar(:something_other_than_baz)
> foo.should_have_received(:bar)
>
> ... should this pass or fail? As rspec-mocks works today, it could only pass
> if we had an additional stub at the beginning.
>
> foo.stub(:bar)
> foo.stub(:bar).with(:baz).and_return(:bam)
> bar(:something_other_than_baz)
> foo.should_have_received(:bar)
>
> ... because calling bar(:anything_other_than_baz) would not work due to the
> with() constraint.
>
> If we agree it should fail, then that's pretty confusing as well, since foo
> did actually receive bar() and the only way to understand to failure is to
> look back at the stub with the with() constraint.
>
> I could go on but I think this makes the point. We don't have test spies in
> RSpec yet because a) I don't personally find them valuable and b) they
> introduce more problems than they solve.
>
> That said, if anyone cares to write an external library to support this, I'd
> gladly work with you to make sure RSpec provides you the extension points you
> need.
>
> Cheers,
> David
It's also worth pointing out that can quite easily write your own test spy for
the odd occasion when it seems necessary:
class FakeExternalService
attr_reader :who_was_published
def publish_user_activation(user)
@who_was_published = user
end
end
> _______________________________________________
> rspec-users mailing list
> [email protected]
> http://rubyforge.org/mailman/listinfo/rspec-users
cheers,
Matt
[email protected]
07974 430184
_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users