Test Driven Development with ASP.Net MVC (Part 1)

In this series of post I am going to talk about how I implement systems in Asp.Net MVC using TDD.  It maybe a little different to some other TDD examples as I am also going to talk a bit about the supporting activities, and the wider thought processes involved.

The series in full:

My thoughts on TDD

A lot of words in books and articles have already been written about TDD, and I am assuming that most readers will have some knowledge of at least the theory behind it. To reiterate the basics:

  • Write a test
  • Watch the test fail
  • Make the tests pass with the most simple implementation possible
  • Write another test
  • Repeat (Red, Green, Refactor)

Software is built through lots of iterations of first failing then passing unit tests. TDD becomes less about testing and more about design as the system is driven out by the fulfilment of tests.

But even for people familiar and competent with the canonical examples of TDD, using TDD together with a more complex multi layered application can be daunting.  Most modern systems fall into that category, and I will attempt to use an example that is a bit more like the situation you may find yourself in in real life.

One of the things I have experienced when using TDD is that every practitioner has their own style, their own ‘flavour’ and dialect for their tests.  I don’t think that there are any right or wrong ways to do TDD, as long as the overall goals are achieved:

  • The design of the application is emergent
  • The logic is exercised accordingly
  • The tests provide confidence when refactoring or adding new functionality
  • The code is inherently testable, through the application of good design principles and practices

My own flavour of TDD for MVC is guided by the flowing principles:

  • Behavioural in nature – When embarking on development it is vital to understand the behaviour of the thing you are going to build.  For this reason, it should be specified in a suitable manner.  My preference is for user stories, with a strong set of acceptance scenarios (I tend to use the Given When Then format) and screen mock ups where possible (Balsamiq is my choice). The tests can then focus on meeting the behavioural needs, not just the technical ones.
  • Vertical Slices – I prefer to work through vertical slices of functionality, so that the User Story and scenarios relate to a discrete piece of functionality that can be tested and demonstrated as a whole.  This is very different from the traditional approach of working through the layers of an application layer by layer.
  • Outside in – I like to start at the outside of an application and work inwards.  Where the “outside” of the application is depends on your approach. For this example I am going to treat the Controller as the “outside” and work downwards towards the data layer.  Other approaches can see the UI layer (the view in MVC) marking the “outside” of the application.  I will discuss how these two approached differ in a short while.
  • Descriptive Naming – I aim to have the test names read as complete sentences that descript the behaviour on test.  It is not an exact science and often undergoes some changes as the tests progress.

Isn’t this Behaviour Driven Development?

People who are familiar with BDD will instantly recognise some of the terminology, and certainly my approach borrows heavily from the BDD movement.  I am reluctant to call this approach BDD for a few reasons:

  • I am not testing the true behaviour of the website from the UI itself; rather I am testing how the controller fulfils the behavioural needs of the UI.  A small difference, but an important one.  A true BDD approach would be to drive the UI with a tool like WatiN  in conjunction with a BDD specific tool like SpecFlow, which can be used as way to test at a feature level, even without having the tests drive the UI, but I think this weakens the overall effect.
  • Although I am focussed on behaviour, the tests are still unit tests (albeit with behavioural names).  The tests are still in the technical domain and do not abstract away all the technical details. Again, a true BDD approach would see the feature tests specified by their behaviour, not their technical specification. Once again BDD tools help with this, but it can add more weight to the process.
In Part 2 the discussion moves to the feature that needs to be implemented.

The series in full: