[rspec-users] mocking errors

Moses Hohman moses.hohman at gmail.com
Sun Jun 24 13:45:23 EDT 2007


Rupert: I assume David wants to do this because he wants to pass a model
object with errors to a view or a controller or something to make sure it
reacts properly to validation errors.

SImplest case:

@mock_thing = mock_model(Thing, :errors => mock_model(Errors, :full_messages
=> ["An error"]))

Hey David and Aslak: I wish I could just say "mock(Errors, :full_messages =>
["An error"])", since I never use the :null_object option on mock(), and I
think it would be better to just have a separate method, "null_object()",
for that case anyway. Is there a reason why that's a bad idea?

If you have lots going on in your mock_model call, you might want to split
this out into a separate stub! call:

@mock_thing = mock_model(Thing, etc. etc.)
@mock_thing.stub!(:errors).and_return(mock_model(Errors, :full_messages =>
["An error"]))

If I needed more methods implemented on Errors than just :full_messages,
then I would rather just use a real Errors object. I don't think you lose
anything by doing this, especially since Errors is a library class and not
one you own. In fact I think you gain something by using the real interface
to this library object instead of a mocked one (to give a more extreme
example, it's better to use a real String than a mock String). In this case
it's nice to write a helper method to decorate the mocked model with an
Errors object:

def mock_model_with_errors(klass, stubs = {})
  model = mock_model(klass, stubs)
  model.stub!(:errors).and_return(ActiveRecord::Errors.new(model))
  model
end

and in the example setup:

before(:each) do
  ...
  assigns[:thing] = mock_model_with_errors(Thing, :a_method => "whatever",
etc.)
  assigns[:thing].errors.add_to_base("An error")
end

Following the Law of Demeter helps reduce the complexity of mocking. In any
situation where Rails frustrates your ability to follow the law (like
ActiveRecord Errors), thereby turning what should be one line of mock setup
into several, I often like to write test helper methods like the above. You
do run the risk of making things less clear in your test, however, so tread
carefully.

I also have this problem mocking ActiveRecord association proxies, where I
need to mock things like client.invoices.find(:conditions => "whatever") in
a controller or something.

Moses

On 6/24/07, David Smalley < david.smalley.lists at googlemail.com> wrote:
>
> What is the correct way to mock out the errors on a Rails model?
>
> I'm assuming i need to say
>
> @mock_thing = mock_model(Thing)
> @mock_thing_errors = mock("errors")
> @mock_thing_errors.should_receive(:full_messages).and_return("An error")
> @mock_thing.should_receive(:errors).and_return(@mock_thing_errors)
>
> Just wanted to check the best practice on this kind of thing and how
> other people handle it.
>
> Cheers,
>
> David
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://rubyforge.org/pipermail/rspec-users/attachments/20070624/66612444/attachment-0001.html 


More information about the rspec-users mailing list