[mocha-developer] Organizing tests and mocha expectations

Bryan Helmkamp bhelmkamp at gmail.com
Mon Oct 9 09:10:59 EDT 2006


James,

Yes, that's exactly what I need!  I need to stub a method in the
setup, and then replace the stub with expectations in specific
tests/specs.  Either that, or stub the method and then be able to
provide expectations for the stub.  There's a slight difference
between the two, but, at least initially, the second way sounds better
because I wouldn't have to duplicate the stubbed return values in the
expectation.

How hard would this be to get into Mocha?  Would it be likely to break
anyone's tests?

Thanks,

-Bryan

On 10/9/06, James Mead <jamesmead44 at gmail.com> wrote:
> On 09/10/06, Bryan Helmkamp <bhelmkamp at gmail.com> wrote:
>
> > I'm simultaneously getting into using Mocha and RSpec-style tests
> > (courtesy of the simply_bdd plugin) and I'm struggling with some
> > issues while trying to organize my specs/test.  Here's a code example
> > illustrating the problem:
> >
> > context "update cliient invalid data" do
> >   include ClientsControllerSpecHelper
> >
> >   specify "should render edit form" do
> >     setup_controller
> >
> >     @client = mock
> >     Client.expects (:find).with("1").returns(@client)
> >
> >     @client.expects(:attributes=).with("attributes")
> >
> @client.expects(:save!).raises(ActiveRecord::RecordInvalid.new(stub(:errors
> > => stub(:full_messages => []))))
> >
> >     @controller.expects(:render).with()
> >     @controller.expects(:render).with(:action => "edit")\
> >
> >     put :update, :id => 1, :client => "attributes"
> >   end
> > end
> >
> > Now, to fit well with RSpec's methodology, I'd like to have a setup
> > method which gets the context ready, and then follow that up with some
> > specifications.  Essentially here's the logic:
> >
> > Update client with invalid data
> > - Should find client by id
> > - Should attempt to save client with new attributes
> > - Should render edit form
> >
> > The problem is that I can't break the expectations up into separate
> > test methods like that because all the tests depend on those in order
> > to work.  It's as if each of those expectations is both setup code and
> > a test, and each test relies on all the setup code for the whole test
> > case.
> >
> > Is  there anyway to reorganize this code to still be DRY but yet also
> > achieve more granular tests, despite their interdependencies?
> >
> > Thanks,
> >
> > -Bryan
>
> If I understand correctly, I think your problem boils down to the fact that
> the mock is providing two pieces of functionality for each expectation - (1)
> asserts that a particular method has been called with particular parameters;
> (2) returns a specified result (stubbing). I'm not overly familiar with the
> BDD style, but the only way I can see you could do this at the moment is...
>
> context "update cliient invalid data" do
>   include ClientsControllerSpecHelper
>
>   specify "should find client by id" do
>     setup_controller
>
>     @client = mock
>     Client.expects(:find).with("1").returns(@client)
>
>     @client.stubs(:attributes=)
>
> @client.stubs(:save!).raises(ActiveRecord::RecordInvalid.new(stub(:errors =>
> stub(:full_messages => []))))
>
>     @controller.stubs(:render)
>
>     put :update, :id => 1, :client => "attributes"
>   end
>
>   specify "should attempt to save client with new attributes" do
>     setup_controller
>
>     @client = mock
>     Client.stubs(:find).returns(@client)
>
>     @client.expects(:attributes=).with("attributes")
>
> @client.expects(:save!).raises(ActiveRecord::RecordInvalid.new(stub(:errors
> => stub(:full_messages => []))))
>
>     @controller.stubs(:render)
>
>     put :update, :id => 1, :client => "attributes"
>   end
>
>   specify "should render edit form" do
>     setup_controller
>
>     @client = mock
>     Client.stubs(:find).returns(@client)
>
>     @client.stubs(:attributes=)
>
> @client.stubs(:save!).raises(ActiveRecord::RecordInvalid.new(stub(:errors =>
> stub(:full_messages => []))))
>
>     @controller.expects (:render).with()
>     @controller.expects(:render).with(:action => "edit")
>
>     put :update, :id => 1, :client => "attributes"
>   end
>
> end
>
> ...admittedly not very DRY, but I don't think DRY-ness is as important as
> readability in tests.
>
> However this reminds me of a conversation I had a while ago with my
> colleague Chris Roos. We were discussing the possibility of replacing one
> expectation with another. If we could do this then it might be possible to
> do something like this...
>
> context "update cliient invalid data" do
>   include ClientsControllerSpecHelper
>
>   setup do
>     setup_controller
>
>      @client = mock
>     Client.stubs(:find).returns(@client)
>
>     @client.stubs(:attributes=)
>
> @client.stubs(:save!).raises(ActiveRecord::RecordInvalid.new(stub(:errors =>
> stub(:full_messages => []))))
>
>      @controller.stubs(:render)
>   end
>
>    specify "should find client by id" do
>     Client.expects (:find).with("1").returns(@client)
>
>     put :update, :id => 1, :client => "attributes"
>   end
>
>    specify "should attempt to save client with new attributes" do
>     @client.expects(:attributes=).with("attributes")
>
> @client.expects(:save!).raises(ActiveRecord::RecordInvalid.new(stub(:errors
> => stub(:full_messages => []))))
>
>     put :update, :id => 1, :client => "attributes"
>   end
>
>    specify "should render edit form" do
>     @controller.expects(:render).with()
>      @controller.expects(:render).with(:action => "edit")
>
>      put :update, :id => 1, :client => "attributes"
>    end
>
> end
>
>
> ...I'm guessing this is more like what you're after. If yes, let me know and
> we'll look into making the change.
>
> --
> James.
> http://blog.floehopper.org
> _______________________________________________
> mocha-developer mailing list
> mocha-developer at rubyforge.org
> http://rubyforge.org/mailman/listinfo/mocha-developer
>
>


-- 
http://www.MyCongress.org/ -- coming soon


More information about the mocha-developer mailing list