We’re all familiar with the term test-driven development now, but it seems a lot of developers still aren’t using it in their normal daily routine. TDD has been in circulation since 2003 or earlier, and has probably been mainstream since 2005. But I’ve worked at companies and spoken to developers at other firms where they admit that they still don’t really follow the test-first approach (and was guilty of it myself when I first started out with unit-testing).
Test-driven (or test-first) development is a whole new mindset and a discipline which you need to practice quite a lot before it becomes second-nature. At first it seems cumbersome and slow, especially when time is precious and the clock is ticking. So the temptation is that you write the implementation first and then write your tests afterwards and make sure they pass. No one will ever know, right? And surely it took the same amount of time as if you’d written it test first? Or possibly even quicker because you’re already familiar with the code that’s being tested? Well apart from breaking every rule in the TDD handbook, maybe you’d be surprised to find that it probably took longer than if you’d written it test first.
To explain, here’s a summary of TDD red-green-refactor development (by the way if you’re not from a testing background, red and green refer to a test framework GUI runner such as NUnit where tests that pass are displayed green and tests that fail are shown in red).
1. Red: Before you write a single line of code, you need to be familiar with the requirement you are about to satisfy. If not, there’s no point starting – how will you ever get the desired end result? The days of hacking out code in the vain hope that by the laws of probability, you might eventually get it right are well and truly over. But in an ideal world you will hopefully have a user story you are familiar with and a particular task you’re supposed to be working on. So once you have a clear idea of what it is you are trying to achieve, write your test first and run it to see that it does actually go red (you may need to stub out the class and method under test before it will compile, but this is OK). You have now achieved two things: you have an automated test which will ensure the integrity of your software over time, and it also describes the client requirement. As such, it documents the expected behaviour of the software which will be invaluable for maintenance over the coming weeks/months/years of the software’s lifetime. By writing the test, it proves (assuming you’ve got it right of course) that you understand the business requirement. And if not, it proves that you didn’t understand it!
2. Green: Now you have a test in place, you can write the code to make the test pass but only write enough code just to make it pass and nothing more. Time = money and no client has ever been happy when software is delivered late. If the test passes, then that requirement has been satisfied and you can move onto the next task (or next user story). Don’t waste time messing around with code if your tests are all green. In the long run this tactic will save you a lot of time and is key to working in an Agile manner.
3. Refactor: Finally (and only if you are running ahead of schedule and have time spare) you can refactor code where the tests are already green. And then – most importantly – re-run your tests to prove you haven’t broken anything. But remember, you’re not doing this for the client’s benefit. You are doing it for your benefit but at the client’s expense. If you go back to a client and tell them that you’re behind schedule because you spent two days refactoring code that was already working, they’ll probably fire you on the spot! OK, maybe not anything quite that drastic but you certainly won’t make yourself very popular.
As developers we always need to justify how our precious (and expensive) time has been spent, so spend it wisely. We are all providing a service to our clients and this means that doing what’s best for the client takes priority over what’s best for us. And delivering working software on time is what they really want, not software that’s beautifully refactored but cost twice as much to build (and ultimately still does the same job it did before the refactor). I’m not suggesting that you start writing unmanageable code which just happens to make your tests pass. But you need to find the right balance between correctly functioning software which may not be very pretty but gets the job done, and correctly functioning software which has had hours of refactoring work spent on it while other areas of the system remain unfinished or have defects. So hopefully you will start writing your tests first and keep your clients happy.