How to improve testability of web applications

Last week I participated in the first Openspace Coding Days in London. The event was organised as a series of ad-hoc coding workshops, and I really enjoyed it. I participated in a very interesting workshop on improving testability of web UIs, that later focused particularly on Microsoft’s new ASP.NET MVC framework. Here are a couple of conclusions we came to:

  • MVC approach in general helps a lot to make web UIs testable as it allows us to test lots of things below the surface of the UI efficiently, including the controller workflow, and just roll back transactions to make tests repeatable
  • Comperensive testing above the UI surface (eg through web automation tools) often doesn’t pay off as scripts take too much time to execute and maintain.
  • Automation of stuff below the surface leaves us with more time to do exploratory testing, but some basic automated tests still make sense to do through the web ui as well (eg face saving tests)
  • Rather than testing the formatting through the UI, a better approach is to move complex formatting away from view templates into helper classes which can be unit tested. This also reduce the stuff you need to test through the Web surface.

ASP.NET MVC specific ideas

  • The default (web forms) view engine allows you to put arbitrary code in the view, but view rendering cannot be easily unit tested, so this requires discipline and ensuring that view pages contain only display and formatting code. Going back to the one of already mentioned ideas, complex formatting should be moved to helper classes and not be in the view page as well.
  • ASP.NET MVC doesn’t really provide any special support for unit testing out of the box. There is no equivalent to Monorail’s test HTTP contexts. You can still mock out HTTP objects yourself. However, controller methods that don’t depend on HTTP contexts or sessions can be easily unit tested as normal classes.
  • Using helpers to generate forms makes views more resilient to change as routes are automatically generated based on class properties. So when you refactor controller method names, form targets and properties get updated automatically.
  • Similar approach in the controllers is to use the ExpressionHelper from the optional extension package Micrososft.Web.MVC, which enables us to get calculate routes with a lambda expression, generating the URL for a particular action. Using this rather than hard-coding strings makes controllers more resilient to change, as lambda expressions are strongly typed and refactoring friendly.
  • Although IView has the render method with a Writer argument, because the default WebForms view engine is using HttpContext.Current it ignores the writer and cannot be mocked out. Other view engines do make use of the TextWriter so the view output could be captured for testing purposes from a unit test.
  • The MVC contrib package has some more additional tools to test routes from unit test tools.

We did manage to put together a very simple web application that demonstrates some of these techniques during the workshop, and you can download the source code for that from the Open space code subversion repository.

I really enjoyed participating in the Openspace Code workshops and I’m really looking forward to the next one. Apparently, they are going to be organised every two months. Here are some links to other write-ups:

Photo by Alan Dean

I'm Gojko Adzic, author of Impact Mapping and Specification by Example. I'm currently working on 50 Quick Ideas to Improve Your User Stories. To learn about discounts on my books, conferences and workshops, sign up for Impact or follow me on Twitter. Join me at these conferences and workshops:

Specification by Example Workshops

Product Owner Survival Camp

Conference talks and workshops

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>