[rspec-users] When to use Factories, Mock Models, Mocks & Stubs

me at franklakatos.com me at franklakatos.com
Wed Feb 3 11:07:09 EST 2010


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 Chelimsky <dchelimsky at gmail.com>:

> On Wed, Feb 3, 2010 at 8:52 AM,  <me at franklakatos.com> wrote:
>> 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)
>
> 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 = []
>
>>          @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?
>
> 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
>>
>>
>>
>>
>>
>>
>>
>>
>>
>> Quoting Adam Sroka <adam.sroka at gmail.com>:
>>
>>> On Tue, Feb 2, 2010 at 9:53 PM, Andrei Erdoss <erdoss at gmail.com> wrote:
>>>>
>>>> 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.
>>>>
>>>
>>> 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.
>>> _______________________________________________
>>> rspec-users mailing list
>>> rspec-users at rubyforge.org
>>> http://rubyforge.org/mailman/listinfo/rspec-users
>>>
>>
>>
>>
>> _______________________________________________
>> rspec-users mailing list
>> rspec-users at rubyforge.org
>> http://rubyforge.org/mailman/listinfo/rspec-users
>>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>





More information about the rspec-users mailing list