[rspec-users] Dreading Controller Specs
sfeley at gmail.com
Tue Oct 21 13:35:18 EDT 2008
On Tue, Oct 21, 2008 at 5:45 AM, Rob Lacey <robl at mail.pigdestroyer.co.uk> wrote:
> However, I seem to dread spec-ing out controllers, they end up being quite
> untidy, I think maybe I am approaching them in the wrong way as it probably
> shouldn't be as hard as I am making it.
For what it's worth, Rob, I'm totally with you. The generated code
for controller specs has always felt...well, wrong to me. And it's
been a frustration every time I've sat down to try to write new
controller specs the same way, taking many times longer than it takes
to write the controller.
The bad part has been the work required to set up the stubs and mocks
-- for just the reason you cite. Conforming to the "single
expectation per test" pattern means I have to figure out and stub
every method that gets called and make it return a reasonable value,
and then I have to *mock* each call at least once to confirm that it
gets called. By this point I've essentially written the model
interface twice, which feels like extraordinary extra work -- and it
also feels brittle. Reasonable changes in the model require
unreasonable maintenance in the controller stubs and mocks.
The only reason for all of this work is the principle of code
isolation. You're supposed to make sure you're only running the code
in the unit you're testing -- but because controllers sit at the heart
of your app, *of course* they're going to have a great deal of
interaction with everything else. That isn't wrong and it doesn't
necessarily make the controllers too fat. But it makes the testing
fat. Just stubbing the relationship between model collections and
objects is complex. It also looks screwy -- and it isn't really a
test of the controller. But it has to be done if you're not going to
talk to the model.
There are some cheats, of course. You can make blanket responses to
stuff you don't feel like mocking. The null_object option to RSpec
mocks is such a cheat; so's stub_everything in Mocha. But to me they
feel like copouts, and they return null by default, which is most
often the wrong behavior, so they don't save work. Mock_model and
stub_model are intended for views, and stub_model doesn't isolate you
from the model. There are some extension plugins that do some of the
mocking/stubbing "grunt work" for you, but that reduces transparency
and they don't know about anything but the most common 'formula'
The conclusion I'm starting to reach is that it often isn't worth it.
All these hours of work to avoid talking with actual models... But if
you just plain used the models, so what? Yes, your controller specs
could fail if your model is buggy or unimplemented. But if your
model's properly spec'ed you'll get failures on the bug there too,
pinning the problem down, and the implementation constraint simply
means you can't write models *last*. You'd implement methods on them
before or simultaneous with the controllers that call them. That's
not a bad order of things.
So now I'm experimenting with live models. I'm using simple, basic
factory methods (I use fixture_replacement2) to create objects for my
controller specs to operate on, saved or unsaved as necessary, and
using Mocha to inject expectations into the actual objects for
specific examples. I may look at not_a_mock for that, too, now that
it's being talked about here. This may not be as philosophically
pristine as total isolation, but it's simpler and cleaner. You don't
have to replicate fake model complexity it in the controller spec.
Most of the lines in the controller spec are once again about the
_controller,_ not about setting up models. It's also slower, but
only a bit. Even with autospec, waiting on my tests to begin is
already slow enough that I don't feel it makes a huge difference. I'm
documenting my approach, too, and what I've been thinking and learning
about RSpec from a "thoughtful beginner" perspective, and hope to have
something I can post on that soon. (That documentation is, in fact,
one of the motivations for my current project.)
That's my take. It's working for me so far, but with the caveat that
I haven't carried a project through to completion with this approach.
If any of the _cognoscenti_ can offer reasons why this is a horribly
bad idea that'll blow up in my face sooner or later, I'm open to being
convinced. I also offer my apologies if this is a topic that comes up
on this list over and over again, and if my little rant here is a
common and tired one.
Steve Eley (sfeley at gmail.com)
ESCAPE POD - The Science Fiction Podcast Magazine
More information about the rspec-users