I’ve come to realize how anti-web 2.0 this blog really is. Why are we, the authors, doing all the work?! Where is the user generated content? How can we pretend to be Rails developers when we waste our time writing all these blog posts!
No longer. Today all that changes. It’s time you guys start pulling your weight.
Let’s Talk About Testing Views
There seem to be about a bajillion different solutions to the ‘problem’ of testing views. If you’re into testing and also into Rails, my guess is you’ve tried a few different styles before settling on your current method. (hey, me too)
What I would love is for you to post your current, favorite, flavor-of-the-month style of view testing. What library do you use, where can we download it, and how about some sample code?
When commenting, wrap your code in <code>code tags</code> and use "textile":http://textism.com/tools/textile/ for links.
Everyone has different taste, but the hope is we’ll have enough options for people to find something they like. Something tasty.
Hit me!
FIRST POST! jk
I’ve been using a plugin I call body_matcher lately. It’s similar to some of the other Hpricot-based plugins out there, but more up-to-date with Hpricot and also pluginized.
From the README:
This is test/spec syntax (body), but it works fine with test/unit using @response.body. I don’t know yet if it works with RSpec—I imagine it does, but if not I’ll take a patch.
Grab it:
$ svn export svn://errtheblog.com/svn/plugins/body_matcher
Oh yeah! I’ve also been playing with this form test helper plugin, which lets you actually submit forms. Kind of like an integration testy thing. Kind of like awesome.
I don’t. Does that make me a bad person? I’ve played with a few options but I find getting designers producing non-brittle easily testable designs really hard work. Has anyone else had that problem?
I was going post this great comment about view testing, but when I found out it was only for Web 2.0 sites, you can forget about it. Call me disappointed.
Seriously, though, when Truthiness is the featured article of the day on Wikipedia, you know we’ve done something right with this internet.
John: Not at all. Do you write tests at all? If so, do you test your controller’s assigns? What I try to do is leave the internal state of my controller alone (aka never test assigns) and make sure the stuff I want shows up. So instead of testing that assigns(:posts) has 10 posts and the first one is this post, I test that this post’s title shows up on my page with a regexp. Using body matcher. That way (ideally) I’m more focused on the data I know should be displayed than any sort of presentation or markup.
You are not a bad person. I still love you.
I don’t test views automatically. I don’t know if I’ll do it in a near future but for now I only test my controllers and my models.
What I do is writing several validation tests that must pass so that the view is validated, and I run them manually.
I think even if I coded automatic tests for my views I would have to test them manually also to make sure Javascript/Ajax code works correctly on Firefox and IE 6 which sadly is not as obvious as it seems…
For HTML forms, I use my own hpricot_forms plugin
RSpec view tests/examples FTW!
lynx localhost:3000 FTW!
RSpec “response.should have_tag” ftw
(wrapper for Rails assert_select which is btw totally awesome)
Also the SpiderTest plugin is very good for checking that your html is valid and all your links work.
RSpec view unit specs – much better than the “functional” hybrid controller/view tests in Rails.
To be honest, I take testing views for granted, it’s easy in RSpec. Until I saw the full post, I thought this article was referring to full-stack functional testing, which I haven’t had time to try. ( Possibly because I spend spend too much time debugging? :D )
I found when i test my views together with the controller, I have a lot of stubbing to do to make the view even run. So what i do right now is test my controllers without my views via assigns, and test some critical parts of some views with separate view specs. (should have_tag like mislav said) I keep the testing of the other views to the integration tests that i will write some time (maybe)
I just started testing my views and haven’t arrived at a really comfortable place yet. So far I’m enjoying response.should have_tag though.
I’d like to add my support for view testing in RSpec. It’s gorgeous!
rspec wrapper around assert_select to start. then after that i step up to integration level testing with selenium.
I use Watir for acceptance testing which I find (so far) is enough coverage for the views. In fact that’s what I’m doing right now! Once I’ve moved this last fixture into a scenario!
I wrote up this not too long ago, which was a RSpec version of how Jamis Buck recommended you test your views.
Chris, I JUST started using using RSpec (Monday), and hated the views testing, so this was a very timely post. Thanks.
I’ve tried your body_matcher, but it fails to work under RSpec under Windows (note I’m running Rails 1.2.4, so I’m a wee bit behind there). Running autotest, I receive:
I use RSpec view testing w/response.should have_tag, as someone else mentioned. I only test the dynamic stuff in a page.
My big problem is how to test javascript code in my pages. Watir or Selenium can both work, but they won’t run in my CI environment.
I use RSpec view tests, loading up some fixtures, assigning them to instance varabiles (to be used in the tests) then putting all the instance variables in assigns[] (via a helper).
But I find them seriously lacking in a few respects. First, there’s no way to specify the order of items. Another problem is that when the assertions fail, the error messages are not at all useful. And it’s really cumbersome to specify input fields; some helpers for that are definitely in order.
So I don’t test nearly as much as I should. I don’t do a very good job at testing the view logic either. (In the future, I’ll probably test the view logic more than my current testing to see if the right variables get output.) And I haven’t figured out how to test partials yet.
Why test views? Ha. I test the output of my presenters, but most of my views do so close to nothing that testing them seems like an extra load – when I do change them it’s usually so drastic that any old tests I had would fail, so there’s not much of a refactoring safety net their either.
On the other hand, I have a big set of Javascript Specs that I run when I’m making big changes to my browser application. My Spec.js library is not pretty, but it handles async actions pretty well. Maybe it’ll help someone…
Chris Anderson’s post above kind of echoes my sentiment, why test the views? Why put logic in your views? Why not move all the logic into helpers or presenters and just test them there?
I’ve tried some of the approaches already listed, including using body matchers and rspec views. Body matching is something I’ve done since I started writing rails but I’ve never been in love with it, Rspec view testing is something I tried briefly and didn’t like.
So here’s a different method which worked well for me:
Move all of your view logic or as much as possible into helper methods and use rspec helper tests on them. Typically I end up mocking calls and then regex matching the output.
The side effect is that you end up pulling logic trees out of the views and burying them in the helpers, which results in a view that is mostly just html and tags. This made me a hit with the designers.
Tim if you move all your logic into helpers and test those helpers. How do you test that the views are calling the correct helpers?
For example if I write a helper to display_foo and write specs that display_foo does what I want. I want assurance that view bar (or partial bar) actually makes a call to display_foo. I don’t care about what it returns, I just want to make sure it gets called.
Have any ideas on this for rspec? Is there value in it?
Derek, let’s try an example display_foo:
So assuming that I tested the above helper method, where two different conditional paths are tested to make sure the right link is rendered, I think you are asking me how then to test the view is calling this helper?
The answer for me, is that I don’t. I don’t spec or test the structure of my views because I don’t find that it’s worth it. By structure I mean stuff like tags, so I won’t spec that a form has 3 textboxes, a check box, and two text areas, because these items don’t contain logic that gives me cause for concern. Also lumped into structure would be calls to helper methods.
I find that if I put logic into helpers and spec them, and I write integration tests, and I write controller tests both functional and unit, and I write models tests both functional and unit. Then an acceptable trade off for me is not to bother with view tests because they don’t pull their weight in terms of effort expended vs. value returned.
Wow, this turned out better than me or any web 2.0 proponent could have hoped. Thanks for all the insight guys—let this page stand as a testament to the power of crowd sourcing the social graph!
This blog will degrade into “my cat was sick this morning”, I bet.
Asking people questions… bah.
Psst: I use assert_select.
We spec our views. I am leaning toward refocusing that effort more toward functional/integration testing.
I think the best way to test views is not to test them. Extract all logic from the view into a model or presenter, where it can be unit tested. Your views are then almost purely declarative and there’s much less need to test them.
Here’s an example of the “presenter pattern”.
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. 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:
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 (introducing defects later); but since views are so variable it’s the one part of your application that you want to minimize regression testing.
That said, view specs are still useful sometimes, just not as often as people think.
Has anybody managed to make bodymatcher work on rspec?
My cat doesn’t seem quite like itself today. Suggestions ?
Have you asked Dr Phil?
My cat was also sick this morning.
Ok, I don’t have a cat, so, seriously.. my approach is similar to Tim Case’s. I do tend to test views so that they at least 1) render 2) contain valid markup. But I don’t test actual structure of the markup, with the possible exception of using class and/or id selectors, like
assert_select ”#ticket-42” do assert_select ”.summary” do ... end end
as for the presentational logic, I tend to use helpers too and test them separately. As such my tests won’t detect missing call to some helper, but it’s kind of an error you’ll usually notice yourself quickly. I have never run into situation where I forgot to put the call to helper in the view, added the call, and inadvertently took it away later on.
When programming, I try to be as pragmatic as possible and just omit testing when effort expenditure/return value ratio is high enough – especially if erroneous functionality is immediately evident.
UI automation tools have a bad reputation.
But recent tools like Watir or InCisif.net use languages like ruby, c#, vb.net, python and their associated IDEs and debuggers. There is the potential to write reliable UI testing.
I still do not understand how you test javascript code in a view or user interaction client side without a UI automation tool.
I’ve actually stopped bothering to specify views, because the view specs are redundant when you start using the RSpec Story Runner.
Etc…
This is actually obsolete already, since plain text stories have been out for a few weeks now, and are even sexier…
Nick Kallen: “since views are so variable it’s the one part of your application that you want to minimize regression testing.”
The fragility is a concern. But the coverage is fantastic, and you can invest in making it very cheap to review and accept changes
Concretely, I wrote this Contentful plug-in
Frederic Torres, (or since it’s been a while whoever shares his thoughts and happens to sumble across this) the only solution to that I’ve seen is selenium. but selenium returns us to the problem of fragility, something of a cross between selenium and the contentful plugin or Watir could do the trick.
For the most part, I just assert that the body contains certain text. This heuristic makes tests less brittle, which allows you to change the layout without causing the test to fail.
When I need to know about a certain tag, like links or forms, I use Hpricot. I also have some custom spec matchers like:
Also, Erector makes views easier to test because you test the output of widget objects that you define. This is more straightforward than testing rails view objects because Rails views objects are quite complicated and tightly coupled to the controller.
Ooh, and finally, for some projects I cache my view generation in a describe block. This allows multiple Examples (its) on the same content without the speed penalty.
Here is a contrived example (normally I wouldn’t worrk about some of these assertions):
Chime in.