When to use Factories, Mock Models, Mocks & Stubs

Hi guys, been following for about 3 weeks, first question -

I’ve been spending the last couple of months learning RSpec and
Cucumber and I’m just finally starting to see the “big picture”, at
least I think I am. But I’ve got some questions I was hoping you guys
can clear up. I’m sure this has been asked a lot, so please bare with
me. Just let me know when my logic is wrong or when I’m way off
course. You guys have been a kind group, so I’m not to concerned with
sounding foolish.

I’ve been using .should_receive and .stub to let my spec know that my
controller is going to be making a method call. I know .should_receive
will fail when you don’t call that method (or if you call it more
times than you said you would) and I use stub when It’s going to get
called an unpredictable amount of times, like in a before block. To
me, it sounds like I don’t really know what the difference is, and I
just have some understanding of there symptoms.

When i need to talk about a model, I usually use mock_model. I have
Factory_girl, but I’ve heard that you should be careful when using
Factory girl, as it ties you down to the requirements of the
attributes, and not the overall functionality (although, that
statement may not be true in itself). So normally, I use Factories in
Cucumber, as that is concerned with more higher level usage features,
and mock_models for controller/model specs.

Alot of times, however, I feel like I’m doing way to much work to get
the whole thing working. Maybe I am, maybe I’m not, only way is to
show off what I’m doing.

app/controller/projects_controller#create

def create
@client = current_user.company.clients.find(params[:project]
[:client_id])
@project = @client.projects.build(params[:project])
if @client.save
flash[:notice] = “Added: #{@project.name}”
else
render :new
end
end

spec/controller/projects_controller_spec

describe ProjectsController do
describe “POST ‘create’” do

 before do
   @current_user = mock_model(User)
   controller.stub(:current_user).and_return @current_user
   @company = mock_model(Company)
   @current_user.should_receive(:company).and_return @company
   @clients = mock("Client List")
     @company.should_receive(:clients).and_return @clients
 end

 describe "when client is found" do

   before do
     @client = mock_model(Client)
     @clients.should_receive(:find).and_return @client
   end

   describe "on successful save" do

     before do
       @projects = mock_model(ActiveRecord)
       @client.should_receive(:projects).and_return @projects
       @project = mock_model(Project)
       @projects.should_receive(:build).and_return @project
       @client.should_receive(:save).and_return true
       @project.should_receive(:name).and_return "New Project"
     end

     it "should set up the flash" do
       post "create", {:project => {:client_id => 1}}
       flash[:notice].should_not be_nil
     end

    end

 end

end

end

Let me know how it sounds, and it looks like I’m doing so far

Thanks,
Frank

Hello Frank,

From my understanding these are the roles of should_receive and stub.

should_receive checks to make sure that a method or a property is
called. To
this you can specify the arguments that it gets called (.with()), what
it
returns (.and_return) and how many times this happens (.once, .twice
etc).

stub on the other hand is a place holder for functions calls that have
been
tested already or are Rails defaults, which don’t need to be tested.
stubs
are used in conjunction with mock_models, in order to provide for the
functions or properties that are needed for the code to run, up to the
test
point.

As far as mock_model and Factory_girl, I can say that mock_models are a
much
more lightweight structure than Factory_girl object. When testing
controllers I try to use only mock_models. As far as models, I use
Factory_girl only when dealing with the object being tested. The other
complementary objects are mocked by using mock_model.

On Tue, Feb 2, 2010 at 9:53 PM, Andrei E. [email protected] wrote:

are used in conjunction with mock_models, in order to provide for the
functions or properties that are needed for the code to run, up to the test
point.

I think that it is best to think of these in terms of command query
separation. In case you aren’t familiar with that principle, it states
that some methods are commands - they tell an object to do something
but don’t return anything interesting, and other methods are queries -
they return some interesting value but have no side effects.

should_receive is how we set an expectation for a command. We don’t
really care what a command returns but we do care that it gets called.
should_receive literally says that the command should be called with
the given parameters.

stub is how we handle a query. We care what a query returns, or rather
the code we are testing does, but we don’t really care when it gets
called (or how often) per se. If we depend on its result then it
should be called, but the effect that the result has on the system
we’re testing is what we really care about.

On 3 Feb 2010, at 11:35, J. B. Rainsberger wrote:

I find this rule of thumb helpful: stub unless you’re certain to want
to verify this time that the client invoke the server correctly, and
never, never mock multiple methods at once.

Right, because the mock (should_receive) is an assertion, and it’s
usually better to have one assertion per example.

cheers,
Matt

+447974 430184

On Tue, Feb 2, 2010 at 19:00, Frank L. [email protected] wrote:

Hi guys, been following for about 3 weeks, first question -

This might help a little: http://bit.ly/ONpXE

To bring things back to Rails, I use mock_model whenever I want to
design controller behavior without relying on the underlying model
behavior. I tend to start using mock_model and mostly stubbing model
behavior, then as controller behavior begins to reveal itself as model
behavior, I push that into the model and mock those methods more
frequently.

I find this rule of thumb helpful: stub unless you’re certain to want
to verify this time that the client invoke the server correctly, and
never, never mock multiple methods at once. If you want to mock
multiple methods, you probably have too complex an interaction.

 end
 @company = mock_model(Company)
 end
   end

end

end

Let me know how it sounds, and it looks like I’m doing so far

Not bad, but I’d probably extract a method for

current_user.company.clients.find(params[:project][:client_id])

and possibly for

@client.projects.build(params[:project])

in order to reduce the number of details that have to go into a single
spec.

def find_client_for_current_user(client_id)
current_user.company.clients.find(client_id)
end

def build_new_project(client, project_attributes)
client.projects.build(project_attributes)
end

def create
@client = find_client_for_current_user(params[:project][:client_id])
@project = build_new_project(@client, params[:project])
if @client.save
flash[:notice] = “Added: #{@project.name}”
else
render :new
end
end

Now I can write these specs:

stub each of the methods in the first three columns…
find_client | build_project | save || expected_result
valid | valid | true || added project
nil | valid | shouldn’t happen || exception (?)
valid | fails | shouldn’t happen || exception (?)
valid | valid | false || errors; render new

and finally:

  1. stub :find_client to answer mock_model(Client); controller should
    receive :build_new_project with the mock model
  2. stub :find_client to answer nil; controller should not receive
    :build_new_project
  3. stub :find_client to answer mock_model(Client); mock model should
    receive :save

That’s the initial spec list I’d write.

J. B. (Joe) Rainsberger :: http://www.jbrains.ca ::
http://blog.thecodewhisperer.com
Diaspar Software Services :: http://www.diasparsoftware.com
Author, JUnit Recipes
2005 Gordon Pask Award for contribution to Agile practice :: Agile
2010: Learn. Practice. Explore.

On Wed, Feb 3, 2010 at 8:18 AM, Matt W. [email protected] wrote:

On 3 Feb 2010, at 11:35, J. B. Rainsberger wrote:

I find this rule of thumb helpful: stub unless you’re certain to want
to verify this time that the client invoke the server correctly, and
never, never mock multiple methods at once.

Right, because the mock (should_receive) is an assertion, and it’s usually
better to have one assertion per example.

Over here to the east of the pond, we say “expectation.” :slight_smile:

Ok, so these ideas seem kind of natural to me, which is nice:

mock_models being used to mock non-tested models
stub for queries and/or well-tested methods, should_receives for
commands

While reading over Dave Astlels, I kind of got concerned because of
something he states that I feel I’m doing in my specs:

“When you realize that it’s all about specifying behaviour and not
writing tests, your point of view shifts. Suddenly the idea of having
a Test class for each of your production classes is ridiculously
limiting. And the thought of testing each of your methods with its own
test method (in a
1-1 relationship) will be laughable.”

This is what I am striving for, but being guided simply by rSpec error
messages results me in writing specs like this…

describe “POST ‘create’” do

 before do
   @current_user = mock_model(User)
   controller.stub(:current_user).and_return @current_user
   @company = mock_model(Company)
   @current_user.should_receive(:company).and_return @company
   @clients = mock("Client List")
   @company.should_receive(:clients).and_return @clients
 end

 describe "when client is found" do

   before do
     @client = mock_model(Client)
     @clients.should_receive(:find).and_return @client
   end

   describe "on successful save" do

     before do
       @projects = mock_model(ActiveRecord)
       @client.should_receive(:projects).and_return @projects
       @project = mock_model(Project)
       @projects.should_receive(:build).and_return @project
       @client.should_receive(:save).and_return true
       @project.should_receive(:name).and_return "New Project"
     end

     it "should set up the flash" do
       post "create", {:project => {:client_id => 1}}
       flash[:notice].should_not be_nil
     end

   end

 end

end

… for a controller that looks like this …

def create
@client =
current_user.company.clients.find(params[:project][:client_id])
@project = @client.projects.build(params[:project])
if @client.save
flash[:notice] = “Added: #{@project.name}”
else
render :new
end
end

Am I doing the 1-1 thing that BDD specifically set out to avoid?

Quoting A. Sroka [email protected]:

To say thank you for all your constuctive feedback would not be
enough; all these insights are really helping me to get the provebial
“it”.

Dave, I completely agree that the mock_model(ActiveRecord) was
bizzare, but my specs kept failing because @projects was to receive
.build, and it complained it didn’t know about it. Using AR fixed
that, but that must have been from a while ago, because I put [] back
in it’s place (which i had before) and the spec passes.

I absolutely love the idea of encapsulated the daisy chained calls
(c_u.comp.project) into a controller methods so all i gotta do is stub
that out. So that makes me wonder – as of right now, I write this
long spec, which looks way more involved than the controller itself.
And, I’d be lying if I said that I thought about my spec first before
writing the app code. Is the idea that I should be trying to think of
a simpler spec, which will force a simpler controller (like
encapsulating functionality into more controller methods)

Once again, thanks++
Frank

Quoting David C. [email protected]:

On Wed, Feb 3, 2010 at 8:52 AM, [email protected] wrote:

for each of your production classes is ridiculously limiting. And the
controller.stub(:current_user).and_return @current_user
@clients.should_receive(:find).and_return @client
end

 describe "on successful save" do

   before do
     @projects = mock_model(ActiveRecord)

This is a little odd. @projects is a collection, not a an instance,
and mocking ActiveRecord explicitly seems a bit odd. I’d generally us
a simple array:

@projects = []

   end

… for a controller that looks like this …
end
end

Am I doing the 1-1 thing that BDD specifically set out to avoid?

1-1 example per method is probably a red flag, but 1-1 spec file per
implementation file makes navigation easier, so I think it’s actually
a good thing.

The underlying problem with 1-1 mappings stems from IDE’s that will
make an empty test case by reflecting on an untested object. You’d end
up with 50 line long test methods named “testGetName” that actually
contain 20 different tests in the one method. That’s an extreme, but I
used to see that sort of thing all the time when I was consulting, and
it makes it very difficult to understand what is being tested and what
went wrong when there is a failure.

Make sense?

  • David

On Wed, Feb 3, 2010 at 2:07 PM, [email protected] wrote:

I absolutely love the idea of encapsulated the daisy chained calls
(c_u.comp.project) into a controller methods so all i gotta do is stub that
out.

Oooh, I hate that one :slight_smile:

You’re adding lots of small methods that actually don’t define how the
class should behave, IMO.
In fact, how a client or project is related to a user is a
responsibility of the models, not the controllers.

I would much rather turn

@client =
current_user.company.clients.find(params[:project][:client_id])
@project = @client.projects.build(params[:project])

into

@client = current_user.find_client(params[:project][:client_id])
@project = @client.projects.new(params[:project])

And add the helper method on the models. Even more:

@project = current_user.add_project(params[:project])

And let the handling of the client and the business rules (“a project
must belong to a client”) to the models, as well

Then your controller would be a lot slimmer, and the tests for it much
simpler.

def create
@project = current_user.add_project(params[:project])

if @project.save
flash[:notice] = “Added ‘#{@project.name}’”
redirect_to somewhere
else
render :new
end
end

Cheers,
-foca

2010/2/3 Nicolás Sanguinetti [email protected]:

responsibility of the models, not the controllers.

And add the helper method on the models.

I strongly agree. Extracting the methods to the controller is merely
an intermediate step. If the methods belong on other objects, then
that tends to become clear soon enough.

J. B. (Joe) Rainsberger :: http://www.jbrains.ca ::
http://blog.thecodewhisperer.com
Diaspar Software Services :: http://www.diasparsoftware.com
Author, JUnit Recipes
2005 Gordon Pask Award for contribution to Agile practice :: Agile
2010: Learn. Practice. Explore.