[rspec-users] Mocking, changing method interfaces and integration tests

Pat Maddox pergesu at gmail.com
Fri May 25 18:49:22 EDT 2007


On 5/25/07, Courtenay <court3nay at gmail.com> wrote:
> On 5/25/07, David Chelimsky <dchelimsky at gmail.com> wrote:
> >
> > As for mocks tying you to implementation - I see a strong relationship
> > to how well you follow "Tell, Don't Ask" and the value you get out of
> > mocking. If you're doing a lot telling instead of asking, you have an
> > implicitly more loosely coupled design. But if you want to make sure
> > that the object being described does the telling, there's no better
> > way to do that then with a mock in my view.
> >
>
> David, Pat, Ruy:
>
> I think this is a failure of Rails for letting us talk to the DB from
> our controllers. For example
>
>   def show
>      @user = User.find(:first, :conditions => { :id => params[:id] },
> :include => :images)
>   end
>
> This kind of thinking then pervades throughout the entire 'rails way'
> of doing things.
>
> This makes it hard to refactor, and just horrible to mock.

Yeah, I think that sucks.  I think I made a post about it a while back
regarding how to spec it.

it "should find the user, including associated images" do
  User.should receive(:find).with(:conditions => { :id => params[:id]
}, :include => :images).and_return @mock_user
  do_get
end

Ummm..............no

> I can
> never think up a catchy name for this, (i'll use find_inclusive for
> now) but ...
>
>   def show
>     @user = User.find_inclusive( params[:id] )
>   end

What about User.find_with_images or User.find_and_include_images

> This works on the idea that, "What if 'find' were a private method?"
>
> Now we can mock User.find_inclusive in the controller spec; we can
> refactor the entire user model, change the database implementation
> (:include something else) and, in an extreme case, you only give an
> external coder access to particular models knowing that other code
> wouldn't be touched (yes, I've done this in the past. Yuk.)
>
> Now, on a large or distributed team, hell.. any size team.. if someone
> goes and changes find_inclusive, and the user-model spec breaks, they
> are responsible for ensuring that the failing spec is NOT altered;
> rather, that their code respects the old API and the spec passes, in
> addition to their fixes.
>
> Finally, higher-level tests (whether selenium or rails' integrations)
> will help you test the whole stack; I still don't believe that
> controllers should_hit the db :)

The situation that really burned me, and led to me hitting the db from
controller tests, is one in which I was creating several related
objects.  I'd create a company, and that company had a before_create
method that created a site for it.  A Site would need to create its
own settings.  In the model specs, each level worked fine (I only
tested creating an object and the child object, not all the way down).
 But in production, foreign keys in the child objects just weren't
being set.  My code didn't work even though my specs said it did.  Of
course that's because my specs just weren't good enough, but if I had
integration tests (even if they're done in my controller spec), I
would have known that.

Pat


More information about the rspec-users mailing list