Monday, February 18, 2008

Rspec View specs and integrate_views

We've recently had the pleasure of having Craig Ambrose working on a project for us, and as you'd expect when you bring someone new into the team, we've been doing some storming. One of the topics that comes up repeatedly within development teams I'm familiar with, including ours, is how fanatically we should adhere to clear separation of unit and integration testing.

I'm fairly laissez faire about the issue. I'm quite happy to write tests for Rails models that actually invoke ActiveRecord and interact with the database. I'll also happily set up a network of associated objects in the database rather than mock out everything except the class under test, though I do have some ill-defined limit that makes me uncomfortable.

I'm more strict about controller tests - I want the controller itself to be wafer thin, and I'll generally only test that the controller sets the right instance variables (along with flash notices etc). The tests end up being fairly small, don't touch the view at all, and I think even the evangelical TDD folk would call them unit tests.

However, Craig rightly points out a couple of problems with this. I'm typically working with server side functionality (if I had to say what I was best out, I'd initially claim domain modelling), so I write crap view code and I rarely write tests for it (someone's just going to come along and rewrite it to be presentable anyway). It's a fairly pathetic defence of my laziness, but anecdotally it seems lots of people don't write view specs. So there's a whole area of my application that's not tested very well.

Craig also points out that one of the biggest sources of defects for him is that his controller doesn't set up what the view expects (or you can express if from the opposite perspective if you prefer) - the failure occurs during the interaction between the controller and the view. These sorts of failures are quite difficult to find with unit tests alone, and probably won't get picked up by distinct controller specs and view specs.

We could write separate integration specs, but RSpec gives a simple way to catch at least the most egregious of these problems. Unit testing purists might object, but the laissez faire'sts won't mind. Put "integrate_views" into your descriptions. When integrate_views is specified, RSpec renders the real view rather than mocking out the rendering, and if objects are missing or badly misconfigured you'll get a rendering exception.

I remembered the integrate_views option from earlier versions of RSpec - it's not particularly conspicuous in the current version's documentation, but it can be very useful.

No comments:

Post a Comment