Software. Agile and Extreme.

Test Driven Development enables developers to not only ensure that their code works at a technical level but also that performs the right business function. Often a difficult adjustment for developers to make, TDD done well enables a dependable and durable code base is created which isn't fragile in an ever changing environment.

TDD: Write the right code right

I'm going to paint a quick scenario and see if it sounds familiar to you:

Day 1. A new project is starting and no code has been written. Everyone has the latest version of Visual Studio and .Net. We're going to use the latest patterns and practices and Agile. New hardware abounds. People are in the office early.

Day 78. The business is asking why we didn't deliver the new "whizz bang" on time. Two weeks ago it wasn't even on the agenda. To implement "whizz bang" we needed to refactor the entire core which broke the "whoop whoop" due to time pressures. The fan on my laptop is annoying. People taking long lunches now.

Tests are our touchstone

You can have all the best tools, hardware, methodologies and people but things will still screw up if you don't have a hardcore approach to testing your code. As projects mature, the code base typically becomes complex. A good architecture and sensible use of design patterns will mitigate the risk associated with that complexity but weak testing will guarantee that eventually a tipping point will be reached and meltdown will occur. I love the term Software Entropy not just because it describes what happens to code over time but also because there's a sort of universal inevitability to it.

And things do change over time. That's why Extreme Programming and Agile methodologies came about. However, it's a lot more than just the code that changes. Environmental changes such as hardware, networks, operating systems, firewalls, IP addresses, security credentials, certificates, people and so on are all in a state of constant flux throughout the life of a piece of software. We need tests to tell us if our code still works when any of the aforementioned variables change. In an ever changing world, tests are our touchstone.

In a previous post I showed you how to lock down your code to give it consistency and to stop bugs creeping in at the earliest possible stage. Now we need to test that code.

Test Driven Development is often a difficult process for developers to fully grasp. It's difficult because writing tests first makes you think about the code from an external view point. By that I mean that writing tests first makes the developer think (long and hard!) about what it is this code is supposed to do. This is good because traditionally, developers often start coding thinking they know what the final work will look like, realise half way through they'd missed a few things, start refactoring and basically ending up with at best sub-optimal code and at worst, a right nightmare on their hands. So test first helps flush out any misconceptions in a developer's mind.

There are two types of tests we can write to make things rock solid.

Acceptance Tests confirm you are delivering business value

First we have Acceptance Tests which look at whether the functionality being delivered is correct from a business perspective. Acceptance Tests are Black Box tests which look to see whether the inputs and outputs of a system do what it says on the tin. Acceptance Tests don't care how smart your LINQ code is or whether you've used the Strategy pattern correctly. They don't care how you serialize your objects or whether stuff is base64 encoded. However, they DO care that you don't lose money when completing a customer credit card transaction. They care about that a lot. They also care that in the extreme case that you DO lose some of your customer's money that the system screams loudly and clearly. Acceptance Tests are arguably the most important kind of tests you will write as these are the ones which confirm you are delivering business value. In Agile, User Stories should only be signed off when all associated Acceptance Tests have passed in a QA environment.

Secondly we have Unit Tests which focus on how a piece of code works at the technical level. A unit test tests a discrete piece of code and removes any underlying or external dependencies in order to focus on that "unit". By using mocking frameworks such as Moq we can write Unit Tests so that we can control the behaviour of external dependencies by simulating them. By mocking our tests we ensure that for a given set of inputs AND pre-defined behaviour of external dependencies we end up only testing the unit of code we are interested in. A sort of "Have your cake and eat it" approach to testing your code.

One more thing to bear in mind as we progress over the next few posts: Here's a very important point before we start:

Test Code is a 1st Class Citizen!


Don't use fantastic inheritance, polymorphism and extension methods etc. in your production code then get all procedural when you write your unit or acceptance tests! Test code is your friend. Treat it with the respect it deserves because this is the code that's going to let you go out and party before a big release instead of working late hours in the office in panic mode.

In my next post I'll go into detail about writing tests and how in real TDD fashion, tests can actually help to define the code we want to write. We'll set up some Acceptance Tests in a Visual Studio solution using NUnit and discuss how they differ from Unit Tests.

xp tdd agile