I recently saw a test passing when it should have failed, because the person who wrote it used should_not_receive instead of should_receive. Here is a simple example illustrating the behavior: class MyTest def foo puts "hey" end def bar foo end end describe MyTest do it "passes but should fail" do subject.should_not_receive(:foo).once subject.bar end end If I remove the ".once" the test fails, as I would expect. Is this intended behavior? It seems really weird to me. I am seeing this with rspec 1.3.2 and rspec-rails 1.3.4. Thanks, David
David Chelimsky
2011-Nov-06 20:46 UTC
[rspec-users] Weird behavior with should_not_receive
On Nov 1, 2011, at 12:59 PM, David Hofer wrote:> I recently saw a test passing when it should have failed, because the > person who wrote it used should_not_receive instead of > should_receive. Here is a simple example illustrating the behavior: > > class MyTest > def foo > puts "hey" > end > > def bar > foo > end > end > > describe MyTest do > it "passes but should fail" do > subject.should_not_receive(:foo).once > subject.bar > end > end > > If I remove the ".once" the test fails, as I would expect. > > Is this intended behavior? It seems really weird to me. > > I am seeing this with rspec 1.3.2 and rspec-rails 1.3.4.It is really weird, but it''s also a misunderstanding of the API. should_receive(:foo) defaults to an expectation of 1 time. The object then exposes methods like once, twice, exactly(3).times to specify/modify the expectation: foo.should_receive(:bar).once foo.should_receive(:bar).twice foo.should_receive(:bar).exactly(3).times Yes, I was sorely tempted to support foo.should_receive(:bar).three_times_a_lady when we added all that, but I refrained. Now that Siri will reenact the entire "Who''s on first?" routine, I''m reconsidering. That aside, to specify that a message would not be received, we used to have to write: foo.should_receive(:bar).exactly(0).times We later added foo.should_not_receive(:bar) as a shorter, more expressive version of that. So, since methods like once, twice, exactly(n).times, at_least(n).times and at_most(n).times all modify the constraint, it turns out that they could be used together, like this: foo.should_receive(:bar).once.twice.exactly(3).times In this case, it would expect :bar 3 times, because the last modification wins. Of course you would never do that deliberately, and in my 5 1/2 years running this project this is the first time I''ve ever seen any issue w/ this, but that is actually not prevented. Therefore, the following are equivalent: foo.should_receive(:bar).exactly(0).times.once foo.should_not_receive(:bar).once Hope that helps you to understand the problem. In terms of what we can/will do about it, I don''t really think we''ll do anything about it but document it better. It would require too much work to solve this without breaking other things, and it turns out that mocha, flexmock, and RR all have the same issue: foo.expects(:bar).never.once flexmock(foo).should_receive(:bar).never.once mock(foo).bar.never.once Cheers, David
Double negatives are not unconfusing. Not unlike chaining mutable decorator objects. (I was tempted to say "non-immutable" but that would chain the jokes) btw with .once and .twice, why not .thrice? Lady or no. -- Alex Chaffee - alex at stinky.com http://alexchaffee.com http://twitter.com/alexch -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20111106/d59039b5/attachment.html>
David Chelimsky
2011-Nov-06 22:55 UTC
[rspec-users] Weird behavior with should_not_receive
On Nov 6, 2011, at 4:45 PM, Alex Chaffee wrote:> Double negatives are not unconfusing. > > Not unlike chaining mutable decorator objects. > > (I was tempted to say "non-immutable" but that would chain the jokes) > > btw with .once and .twice, why not .thrice? Lady or no.module Thrice def thrice(&block) exactly(3).times &block end end RSpec::Mocks::MessageExpectation.send :include, Thrice There you go :)
On Sun, Nov 6, 2011 at 2:55 PM, David Chelimsky <dchelimsky at gmail.com>wrote:> There you go :) >You are three times a gentleman, David. -- Alex Chaffee - alex at stinky.com http://alexchaffee.com http://twitter.com/alexch -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20111107/07dfe4eb/attachment.html>