The ELC Community Blog
A knowledge exchange on Ruby on Rails and Agile Development
Testing without the database
by Dylan Stamat on December 10, 2007
Everyone seems to have their own opinion about "when" and "if" they should omit hitting the database in their test suites.
The "why" boils down to the time it takes to run test suites... as database contention obviously adds for some longer runs.
The "how" is through mocking/stubbing, which then brings up the mixed opinions on the matter.
Controllers
While I was writing up a summary about this, I realized Mike Clark already did the good deed, and jotted down both a concise overview "and" personal opinions from a bunch of bright cats :) I urge you to read the following posts... and taking the time to follow the corresponding links in the article. His two part article is one that everyone should read:
Part 1 , Part 2Models
This is obviously a bit more controversial than the mocking/stubbing of controllers. I mean, using an inherent ActiveRecord object would warrant the entire driver/database implementation throughout your assertions... right ? Again... let the answer be an excersise to the reader.
UnitRecord by Dan Manges and friends uses schema.rb to create a mock of your models database columns.
Rick Olson has something "somewhat" similar in ModelStubbing
Personal
With all that said... I'm personally a fan of mocking/stubbing controllers, and letting my model tests hit the database.
My controller tests should route requests, alter session / flash state, and manipulate models. The model manipulation doesn't matter here, and these tests belong in my unit/model tests.
I will still take the performance hit, and let my unit/model tests hit the database.
In the end, it's currently a matter of preference and discretion. If I happen to come up with a crazy corner case in my controllers... I may want the database involved. If my model tests became un-reasonably slow, I'd look at mocking/stubbing or cleaning up some of my test cases (with caution).
Would love to hear your opinions on this... and maybe Mike will gather up the troops and do some similar posts in regard to the model side of things :)
Timeline
- Script Terminal with TermInit
- Patching Rails - Rendering form partials
- Open Social plugin progress report
- Notify me when it's done
- OpenSocial on Rails, finally 1.0
- Testing without the database
- acts_as_chattable: make web chatting easy
- OpenSocial Container 0.3.0
- OpenSocial Container 0.2.0
- Mephisto Flickr AJAX Loader
- OpenSocial? What's that?
Comments
I’m still a testing newbie so my opinions might change in the future but for right now I am “hold the onions” sort of guy (as referred to in the second part of Mike’s article). In an ideal world your unit testing will be ensuring that everything the controller expects your models to do are being done. But in the real word you might miss something in your unit testing on your models. So your controller testing using real models may pick up that mistake allowing you to correct your unit testing.
For me the more I move away from my actual code the less I am testing of my actual code. Mocks can be useful but most of the time for me real code is where it is at.
I can highly recommend Jay Fields’ approach to this: http://blog.jayfields.com/2007/09/rails-how-we-test.html
I’ve been testing like this for a few months now and wouldn’t go back. I also like the use of a Factory instead of fixtures as mentioned in the article.
@Eric
Understandable, and coming from a background of straight JUnit with no mocking what-so-ever, I’m almost in the same boat. On large projects however, mocking/stubbing schemes can be justified… as suites can start to creep up to 30+ minutes a run, which is much too slow IMHO. Specifically for simple controllers, authentication, etc… mocking/stubbing makes a lot of sense to me.
@Jamie
I primarily use RSpec, and haven’t found the need to do the unit / functional abstraction for unit tests. I’ve used Presenters, Validateable… etc… and this is the probably the one thing that I haven’t picked up from Jay yet :) Would love to hear a bit more about your likes and dislikes of using this approach. On a side note, I’ve been using a Factory for a while, and definitely prefer it as well :)
@Dylan Do you really need to run your full tests all the time. The default rake files with rails have the ability to run recent and uncommitted tests. Also you can run just the model or controller you are hacking on.
Then occasionally throughout the day run the full test in the background (while you are hacking or are at lunch) to verify nothing affected an unrelated system.
But then again even my largest projects only take about 5 minutes to do the full testings so perhaps I would like mocking if I ran into the time thing more. I guess I am not testing enough. :)
@Eric Good questions ! No, definitely don’t need to be running the entire suite all the time, and will usually use autotest, or, just spec on the code I’m dealing with. Aside from the annoyance of it taking a long time, CruiseControl can get hammered when tons of commits are coming through, and spawning half-hour suite runs. The whole process is still pretty discretionary… and, color me “hold the onions” as well, but I’d rather be safe than sorry :)