[rspec-users] On Mocks vs Stubs in the context of rSpec

David Chelimsky dchelimsky at gmail.com
Thu Jul 23 20:33:12 EDT 2009


On Thu, Jul 23, 2009 at 6:39 PM, Marcelo de Moraes
Serpa<celoserpa at gmail.com> wrote:
> Hello list,

Oi Marcelo,

>
> >From what I could see, the lines between mocks and stubs are subtle,
> but the general idea I got is that mocks set expectations and stubs
> are only dummy objects/method calls. What confused me though, is that
> the stub() method is an alias for mock() in
> Spec::Mocks::ExampleMethods. So a stub is a mock?

The conversation about stubs and mocks are usually about Mock Objects
and Test Stubs - i.e. two theoretically different kinds of objects.
The functional difference between them, however, is really at the
_method_ level, and even then, they are mostly the same:

Both Method Stubs (stub()) and Method Expectations (should_receive()):
* respond to a call
* can return a canned value
* can return different values to subsequent calls
* can raise errors
* can yield values to a block
* etc, etc, etc

Only Method Expectations can verify that they have been received. That
is the primary difference between them.

Keep in mind that these ideas evolved and appeared at different times
and as different things, but over time have evolved to nearly the same
thing with the exception of verification.

The primary benefit we get from verification is when we care about a
specific interaction that causes a side effect that we can not
perceive from the object we're dealing with. Let's say we want to spec
that an object logs something in response to a message given specific
conditions:

describe Account do
  it "logs a message when it is queried for its balance" do
    logger = mock('logger')
    logger.should_receive(:log).with(/queried for balance on/)
    account = Account.new(logger)
    account.balance
  end
end

Note that this spec never expects any values on the account itself.
This is the classic example of the use of a mock object, or more
accurately (in my opinion) a message expectation.

Now in cases like we see so often in Rails controller specs, in my
view there is little difference between these two:

describe ThingController do
  describe "GET index" do
    it "assigns all things as @things (using a message expectation)" do
      thing = stub_model(Thing)
      Thing.should_receive(:all).and_return([thing])
      get :index
      assigns[:things].should == [thing]
    end

    it "assigns all things as @things (using a stub)" do
      thing = stub_model(Thing)
      Thing.stub(:all).and_return([thing])
      get :index
      assigns[:things].should == [thing]
    end
  end
end

In this case, the implicit verification in the first example doesn't
buy us all that much, so the second example does a perfectly good job
and is slightly less brittle.

> Also, another thing that is confusing: You have stub and stub! methods
> in the Spec::Mocks::Methods namespace, what is the difference between
> Spec::Mocks::ExampleMethods#stub and Spec::Mocks::Methods#stub ?

The original method was stub!, which I will confess to introducing,
and for the wrong reasons, due to my misunderstanding of the meaning
of ! in ruby methods.

I recently added stub (with no !) with no particular fanfare, as I
don't intend to remove stub! (at least not any time soon). Right now
the docs don't make it clear, so I need to fix that - but I'd say that
stub() is the method to use and stub!() is there for backwards
compatibility.

Cheers,
David

ps - seu nome pareçe brasileiro - você é?

>
> Thanks in advance,
>
> Marcelo.
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>


More information about the rspec-users mailing list