[rspec-users] Good practices on spec'ing views?

Stefan Kanev stefan.kanev at gmail.com
Fri May 21 09:34:27 EDT 2010


Thank you for your answers!

> In The Rspec Book, section 24.6 (chapter 24), "When I write view specs"
offers some tips for determining when to write view specs. Have you read
this section?

I though I did, but I revisited it and I learned some new things. Thanks!



I did some thinking on my own and I reached some conclusions. I would like
to share them -- it will help me structure my reasoning. I would be happy to
hear what you think. This is going to be long.

I'm assuming that I want to use test doubles in view specs. I don't see much
value in testing model, view and helper code at once. Also, I'm only
checking for the presence of text and occasionally for the presence of a
link. I'm not asserting DOM structure or rendering order.

There is a big difference between using doubles in controller specs and in
view specs. Controllers depend only on the models. Using test doubles in
their specs leads you to a nice, clean public interface of the models and
only a handful of simple messages in the actions. The code is just a simple
moderator. This is what a clean controller should be, in my opinion.

Views, on the other hand, know a lot of tiny details about the models. After
all, they should if they are to present that information in a humane way.
Thus, they are more coupled to the models than controllers. This requires
more intricate test doubles. Furthermore, they also invoke helpers to do
some of the work. Not only you have to mock them too, but most of the time
helpers just take a model and return a result dependent on it. This is
tricky to mock (simplest case you make a mock of the model and set an
expectation on a helper).

That's two problems with test doubles in view specs -- (1) view and model is
more tightly coupled and (2) you have helpers as a depend-on component. At
this point, getting the test doubles right is too much work. The usual
problem that I have, is that as soon as I complete a refactoring in the
model, I have to spend an equal (or even greater) effort to fix the doubles
in spec failures, that are false negatives. I think I've seen this named
'fragile test'.

Thus, my approach would be to avoid writing view specs most of the time and
make sure I've provided the safety net with Cucumber. That is my case
against view specs.

I can see two reasons to write them, though.

First, I can consider it as purchasing technical debt. I write a view spec
instead of a Cucumber scenario for a small behavior modification. This gives
me the safety net for a lower price (view specs take considerably less
time), but the cost is that it hinders refactoring.

Second, if I have something complex to display and no idea now to organize
it, I can use a view spec to drive the design. This let's me base it on
feedback, but when I've implemented the functionality back-to-back, the view
spec has turned into an expensive artifact that hinders further refactoring.
I've done that a few times -- it really helps me with the design, but I find
myself removing the spec after a while since it takes just too much time to
maintain.

I also see two things that might invalidate this reasoning.

First, presenters. They group the model and helpers logic that the view
depends on, so now I would have to mock only one object. More importantly,
that object is specifically designed to be used by the view, which means
that the test double will be simple and that I can use the view spec to
drive the design of the presenter.

Second, moving all logic from the view to helpers that take the model as a
parameter. This should simplify the test doubles, although you still will
have to set expectations on helper invocations. This moves the intricate
knowledge of the models in the helpers, which are easier to test. The view
mediates models and helpers.

I'm not sure if I like the resulting design. While the views look slick, you
have to understand the helpers first in order to understand the view. Logic
that belongs together is scattered around in multiple files, intermingled
with other logic. Also, at this point I don't see much reason to write a
view spec either, since the code that could possibly break is either in
models or helpers, which are tested in isolation. If you insist on doing it,
setting up test doubles is still a bit weird (you have to set expectations
and define results on helpers and you have to use mocks for models). It gets
particularly tricky when the view iterates over a collection and calls a few
helpers with each item.

On the more general note, while controllers are pretty OO in they nature and
thus can tolerate test doubles, views are, well, just procedural Ruby
embedded in HTML. Applying mocks to them doesn't seem a good fit to me.



So, what do you think? Does this make sense? Did I miss anything?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20100521/35836805/attachment-0001.html>


More information about the rspec-users mailing list