Michael MacDonald

Less Brittle View Specs

In Rails, Testing on August 26, 2009 at 8:00 am

View specs are often misunderstood and ignored (poor little things) however I believe they can be useful. A big criticism of view specs is that they are brittle – when your html changes, they break. Another is that Cucumber makes them redundant. A lot depends on how you write them.

View specs aren’t about verifying that your html is correct or that you have applied the correct css to the appropriate dom element. Like other specs, it’s about business requirements. View specs are only brittle when you tie them closely with the presentation of your data.

Meanwhile, I prefer to keep my Cucumber features and step definitions free of implementation details. I just want to verify that the behaviour works, that when I do a particular task I get the outcome I expect. How it happens or how it is presented isn’t really what I care about with Cucumber – it’s an integration test after all.

So, I use my view specs to verify low-level business requirements like “should have a search box”. I’d use Cucumber to verify that the search box works and I’d use view specs to ensure that the search element has a title, an input field and a submit button. The view spec verifies the nitty gritty detail. For example, as a designer I could label the search any way I wish. It’s just text after all. But the business may need to use specific terminology/wording for the title and for the form element labels.

This is where view specs can easily become brittle. If you write them such that they depend on html elements then you are tying them to the implement of the html. If you were ever to change your html, your specs would break even though the actual business requirements would still be met. My advice is to try and eliminate all reliance on the html implementation. Focus on the business requirements.

Here’s a simple example…

The business wants a title of “Candidate Search” for their search element. It would be easy to write:

response.should have_tag('h2', 'Candidate Search')

But that has now tied the text to how the text is presented, in this case using an h2 element. What if we decide to use h3 instead? Spec fail. Try this instead:

response.should include_text('Candidate Search')

You don’t particularly care what element is used, just as long as the text appears on the page. If you need to target then do so. I like to focus on the div or id element as these (should) change less frequently. And what if the designer decides to use the button element instead of the input submit button? Fine, use an attribute selector for type=submit.

The thing to always keep in mind, is not to go overboard. Keep focused on the business requirements and ask whether the tests are adding any business value. I don’t test all aspects of what my views present. Remember, you should try to keep logic out of your views. I test the bits that are important to the business. Yes, there will be crossover with Cucumber features so this is where your judgement comes in.

Here’s my final view spec (using webrat 0.5.1 matchers):

response.should have_selector('#candidate_search') do |search|
  search.should contain('Candidate Search')
  search.should have_selector('form', :action => candidates_path) do |form|
    form.should have_selector('[type=submit]')

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: