[rspec-users] How far to go with ActiveRecord unit tests without hitting the database?

Scott Taylor mailing_lists at railsnewbie.com
Sun Sep 16 13:59:25 EDT 2007


On Sep 16, 2007, at 1:20 AM, David James wrote:

> I'm currently try to push my limits a little bit with some of my  
> unit testing -- trying to avoid saving ActiveRecord objects to the  
> database and take advantage of mock/stub objects.
>
> How far should I expect to get in this direction?  From what I can  
> tell, ActiveRecord seems to fight me when it comes to  
> associations.  In other words, many associations seem to require  
> database queries.
>
> Have others had success in mocking/stubbing associations?  In  
> particular, have you had luck with has_many :through?
>

I would highly suggest taking a look at Jay Fields blog.  The  
examples use Test::Unit, but that shouldn't discourage you :).  In  
one of his posts he stubs/mocks out the class used for a database  
column in ActiveRecord (ActiveRecord::ConnectionAdapter::Column).

I, personally, though, prefer to go the opposite way.  Integration  
Testing and Unit Testing are on a continuum, and in my opinion, the  
only advantage of going the Jay Field's way (that is, the traditional  
mocks/stubs approach - this is the one end of the continuum) is  
speed.  The truth is that Rails was not developed by a BDD'er, and  
the coupling is too tight.  When you test rails the way you would  
test anything else, you'll soon realize how tight this coupling is,  
because you will spend more time debugging rails then debugging your  
own app.

Just as an example, the other day I had a method call in an  
ActiveRecord class which did something like this:
   Tag.find_or_create_by_name("Summer")

and I had the following expectation:

Tag.should_receive(:create).with(:name => "Summer")

So where was my test failing?  It wasn't in the logic of *my* code.   
It was in how ActiveRecord dealt with this dynamic finder.  The docs  
say this:

   Tag.find_or_create_by_name("Summer")  # equal to Tag.create(:name  
=> "Summer")

So I ran my debugger.  Guess what!  The call was to Tag.create("name"  
=> "Summer"), not Tag.create(:name => "Summer").  (The difference was  
that "name" was a string, not a symbol).

So - if you can afford to spend time debugging the internals of rails  
(or if you know rails inside and out) , then yes - go right ahead and  
have incredibly speedy unit tests.  But otherwise, what exactly are  
you testing?

Sorry for the rant,

Scott Taylor


More information about the rspec-users mailing list