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 > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users cheers, Matt m...@mattwynne.net 07974 430184
_______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users