Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Testing Views by Not Testing Views: Or, The Presenter Pattern

Pivotal Labs
Friday, October 19, 2007

Err The Blog asks: “What’s the best way to test views?”

I think the best way to test views is not to test views. Extract all logic from the view into a model or presenter where it can be unit tested. Your views are then mostly declarative and there’s minimal need to test them.

Here’s an example of the “presenter pattern”.

def create_or_destroy_friendship_link(friend)
  if current_user.friends_with?(friend)
    destroy_friendship_link(friend)
  else
    create_friendship_link(friend)
  end
end

You don’t need a special class to do a Presenter; a good old-fashioned layer of abstraction will do. The basic idea is to write all conditional+iterative view logic in such a way as to never call a Rails helper directly, or generate any HTML directly, or generate any strings directly. The logic merely delegates to other methods closer to the metal.

Tests then become fairly simple. Write tests of the higher-level conditional/iterative logic in terms of the lower-level methods:

describe FriendshipsHelper, '#create_or_destroy...' do
  it "renders create link when two users are not friends" do
    log_in(users(:bob))
    bob.should_not be_friends_with(users(:amy))
    create_or_destroy_friendship_link.should == create_friendship_link
  end
end

This minimizes the need for view specs. I find in practice that a high percentage of view tests slow development down””they’re implemented not to aid development (since you typically debug views in-browser), but to prevent regression (i.e., they minimize the likelihood of introducing defects later). But since views are one of the most variable parts of a web application, regression tests are of the least value.

As a side note, I love integrate_views — not because I like to make assertions about the view in my controller tests, but because I hate mocks! I want a controller test to fail if I have a syntax error in my view!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

7 Comments

  1. Adam Keys says:

    I’ve thought of doing something like that, but with helpers instead of pushing the logic into a model (which sounds heretical to me) or a presenter (not so bad). So my two questions:

    • Why not helpers?
    • How do you integrate designers into the fold? Do your presenters then render partials that they can edit?

    Also, I’d be interested to see your approach all the way down, i.e. what does create_friendship_link look like?

    December 12, 2007 at 11:50 pm

  2. Alex C says:

    Why not helpers?

    In Nick’s code example, they are helpers. Notice the reference to “current_user” — that’s a clear sign that it’s in view-land, not model-land.

    How do you integrate designers into the fold? Do your presenters then render partials that they can edit?

    Ah yes, this old bugbear rears its head again. In my experience, UI designers come in two breeds:

    1. Those who stop at mockups, either PSDs or HTML+CSS, and hand those off to the coders, who do the work of translating into dynamically-rendered HTML
    2. Those who are savvy enough to edit code, which means RHTML or Markaby or Ruby or Java, and who aren’t afraid to run a test suite or check in to subversion

    I have heard many legends of a mythical beast, elusive as Sasquatch: the Idiot Savant Designer. He is smart enough to learn HTML, JavaScript, DHTML, CSS, and knows how to lay out his pages in reasonably-chunked reusable components. Yet once having learned these high-level concepts, he is reduced to blubbering infancy at the prospect of coding directly in Ruby or Java — even if that code consists only of functions and print statements. Despite copious references and allusions to this creature in whitepapers and blog posts throughout history, I have never personally made a sighting, nor spoken to anyone who has. As far as I can tell, the ISD is an urban legend, or maybe purposeful disinformation sowed by the promoters of webapp frameworks (in league with the angle bracket industry).

    In short, designers are in the fold in exactly the same way as if we were embedding logic inside template files, only they are writing better code.

    December 12, 2007 at 11:50 pm

  3. nick says:

    I am a heretic, and I believe that putting “view logic” in the model is perfectly OK. Nevertheless, as Alex points out, the above example does none of that. To totally change the topic, Here is my anti-MVC rant:

    MVC is a sacred cow, but we rarely ask “why?” let alone “should?”. Firstly, Rails MVC is a bit of a joke; their are no objects in the view layer, the Controller layer is only vaguely analogous to Controllers in the GUI world, etc.

    Secondly, MVC is not necessarily the best fit for a web app. If you buy into the REST religion, you might think there are only two layers of abstraction–resources and representations.

    Thirdly, many of the most interesting GUI frameworks are not MVC. cf., Morphic which was invented with Self and is now used in Squeak.

    Fourthly, MVC has serious downsides with are rarely acknowledged, namely that there’s a) a parallel class hierarchy (often you simply have one view mapping to one model mapping to one controller), and b) if you want to (e.g.) render a heterogeneous list of model objects you need a factory to instantiate appropriate views; that factory needs to break polymorphism and manually dispatch on type.

    In short, MVC is stupid. Heresy, yes.

    December 12, 2007 at 11:50 pm

  4. Adam Keys says:

    @Alex OK, I thought they were methods on the Presenters. Cool.

    As to the mythical ISD, I agree that finding someone who can go from IA and visual design all the way down to templates is rare, but not unpossible. I know one fellow who can do just that, and even into the depths of Rails controllers and models.

    On the other hand, front-end developers who are saavy with JS, HTML and CSS are often competent enough to deal with Rails views. Plus, they are far more numerous. Unless we make things hard for them by outputing HTML from helpers and whatnot, they can do everything they’re used to doing with a minimum of fuss. But if your helpers rely on partials, then everyone can have their cake, it seems to me.

    December 12, 2007 at 11:50 pm

  5. Riki says:

    Man you don’t even know how long I’ve waited for this since disabling my own Movable Type widget (that doesn’t work since Haloscan bypasses that code).

    December 12, 2007 at 11:50 pm

  6. Frederic Torres says:

    Generally speaking how do you test a javascript code that run in a view let’s say triggered by a click on a button.

    Frederic Torres
    http://www.InCisif.net
    Web Testing with C# or VB.NET

    December 12, 2007 at 11:50 pm

  7. Chad Woolley says:

    @Frederic:

    There are a couple of approaches. First, you can test the javascript in isolation using jsunit. To test the complete page integration, you can use a tool like Selenium. See Pivotal’s seleniumrc-fu project for an integrated package that makes it easy to use these tools ( http://rubyforge.org/projects/pivotalrb/ )

    – Chad

    December 12, 2007 at 11:50 pm

Add New Comment Cancel reply

Your email address will not be published.

Pivotal Labs

Pivotal Labs

Recent Posts

  • Does the set of all sets contain itself?
  • Standup 3/8/2012
  • Standup 3/7/2012
Subscribe to Pivotal's Feed

Author Topics

riddles (1)
agile (167)
capistrano (2)
rails (26)
movember (1)
git (10)
railsdoc (1)
object-design (1)
bdd (3)
cucumber (3)
linkedin (1)
oauth (1)
ruby (17)
tdd (2)
lvh.me (1)
rails 3.1.1 (1)
selenium (6)
homebrew (1)
mysql (5)
rvm (1)
sproutcore (1)
paperclip (2)
pry (1)
amazon (1)
heroku (1)
rails3 (2)
jasmine (3)
design (3)
process (12)
productivity (8)
learning (1)
olin (1)
migrations (2)
mongodb (2)
devise (2)
javascript (13)
rubymine (4)
ipad (1)
whurl (1)
head.js (1)
pairing (2)
tools (4)
pair programming (1)
rspec (10)
rspec2 (1)
ruby19 (1)
incubation (3)
startup (5)
api (1)
presenter (1)
vanna (1)
pivotal tracker (5)
capybara (1)
fakeweb (1)
webmock (1)
intern (1)
ruby on rails (25)
meetup (1)
textmate (1)
testing (20)
solr (4)
nyc-standup (11)
community (1)
opensource (3)
activerecord (4)
chrome (1)
mp4 (1)
activeresource (1)
flash (3)
neo4j (1)
nginx (1)
rsoc (1)
meta programming (1)
agile standup (7)
government (3)
webos (4)
xss (1)
jquery (1)
bundler (2)
ci (3)
gems (5)
postgresql (1)
geminstaller (1)
gemcutter (1)
cloud (2)
rack (2)
refraction (1)
gem (5)
refactoring (1)
validations (1)
webrat (1)
engine-yard (1)
firefox (2)
jsunit (1)
mongrel (2)
thin (1)
unicorn (1)
facebook (1)
rubygems (5)
jruby (1)
actioncontroller (1)
rails 2.3 (1)
palmpre (1)
autotest (1)
mac (2)
hosting (1)
goruco (11)
database (3)
railsconf (11)
gogaruco (4)
deployment (4)
github (1)
ie (1)
ajax (1)
intellij (1)
json (1)
asset packaging (1)
polonium (1)
character encoding (1)
utf-8 (1)
test (3)
civics (1)
hpricot (1)
rake (3)
sms (1)
unicode (1)
iphone (1)
java (1)
safari (1)
memory leaks (1)
rr (3)
editor (1)
css (1)
nyc (3)
performance (5)
fun (5)
enterprise rails (1)
health (1)
new and cool (1)
general (2)
treetop (1)
errors (1)
stack (1)
trace (1)
cache (1)
cookies (1)
freesoftware (1)
conferences (1)
development (1)
driven (1)
proxy (1)
caching (1)
peertopatent (1)
languages (1)
rest (2)
rubyforge (1)
sake (1)
file (1)
upload (1)
constants (1)
osx (1)
terminal (1)
pairprogramming (2)
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >