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
_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to