This is step 7, the final step in a series of articles, starting with Seven Steps To Quality Code – Introduction.
The biggest change in my development practices over the last few years has been has been the introduction of Test Driven Development (TDD). I remember the first project in which I used it and the feeling it gave me. A feeling of confidence. Confidence that the code I had written worked and confidence that I could make changes without worrying about something else breaking unknowingly.
I used to be an assembly language programmer. In that world, there were no helpful debuggers other than the ability to dump the contents of the registers to the screen or maybe post a “got here” message. When I moved to Visual Basic, I was blown away by the fact that I could step through code and inspect the values of variables. This was simply amazing and of course changed the way I developed software.
Discovering Test Driven Development felt just the same. A revolution in how I would code.
So now, a decade after those first steps, I am a big fan of TDD. It suits the way I work (mostly) and really helps to lock in quality.
However, this step in the “seven steps” series is not really about TDD. The series is more about improving what you already have. TDD is great for a new project, but it’s too late for a project that’s already in existence.
I’m going to suggest a few very simple actions to take that will allow you to get some of the benefits of TDD. If you haven’t tried TDD or any automated testing before, it will allow you to get a feel for it in a comfortable environment (i.e. your existing code) without the pressure of going all out on a drive to introduce TDD.
Perhaps at this point an overview of some terminology will be useful. The table below explains a few terms.
|Automated Testing||A broad term that covers any form of testing where test cases are automatically run against the code and verified for correctness.
|Unit Testing||Traditionally, unit testing meant a developer performing their own manual tests on a module/component or other "unit" of software, whether formally or informally. In more modern parlance, it is often used interchangeably with "Automated Testing" above but strictly speaking, the 2 are different.
On one extreme, unit testing means automated testing of a single method - perhaps passing in a series of inputs and verifying that the outputs or the behaviour are correct. Often this will be through the use of "Mocks" (see below) to isolate the unit from any dependencies. Purists will insist that this is the only true definition.
Alternatively, unit testing may mean automated testing of a single class and its behaviour or perhaps a complete software component, though it is more likely that this would be minimal testing of a third party product.
|Mocks||Martin Fowler has written an interesting article called "Mocks Aren't Stubs which describes far better than I ever could, what a mock is. For our purposes here though, we will consider a mock as some sort of software 'thing' used in place of some other software 'thing' in order to isolate the unit being tested and optionally verify behaviour.
|Test Driven Development (TDD)||This is where tests are written before the code and the code is written purely to make a test pass.
|Red-Green-Refactor||This is a phrase that describes the process of TDD. 'Red' refers to the usual indicator against a test showing that it has failed (a red cross perhaps), 'Green' refers to the usual indicator to show that a test has passed (a green tick perhaps) and 'Refactor' refers to the task performed after a test passes, which is to revisit the code and improve it without changing its external behaviour. So, TDD is a repeating cycle of - write a failing test - make it pass - improve the code.
|Integration Test||An integration test is a test that checks that several "units" work together. Sometimes referred to as "end to end" tests because of the desire to verify that the system under test functions as a whole from the beginning of a process to the end.
|Test Prompted Development||A phrase I use that describes a dangerous situation that can often occur in Test Driven Development. I will blog about this in the near future.
What To Do
The suggestions I have are very simple and should start to show benefits very quickly.
Whenever a bug is discovered in code that does not have associated tests, write a test (or tests) that reproduces that bug and fix the bug by making the test pass. Leave the test in the project permanently so that it is possible to verify whenever necessary that the bug has been fixed and has not returned.
This is really no different to how a developer often fixes bugs without automated testing. The really powerful part of it is retaining the test and incorporating it into the project.
Test New Helper Functions
The easiest kind of code to test is often the little helper functions. If you are writing a new function to do something like string handling (perhaps concatenating first name, middle name and surname or something like that), write some tests. Verify that the result is correct when the input values are null or empty, when boundaries are reached or breached. For many functions of the kind I am talking about, you can produce a really solid set of tests that will give you absolute confidence that the code is correct.
Again, make sure the tests are retained as part of the project.
Incorporate Tests into Your Build Process
If you have any form of automated build, include your tests in that process. All build automation systems will support this in an easily implemented way. Ensure that test failures result in build failures and ensure that the failures are addressed as a priority.
As I said at the start of this article, automating provides amazing benefits and allows you to be really confident that your code performs as you expect. A full TDD approach is pretty hard, but if you start by dipping your toe in the water as I have suggested, you can start with little risk and learn the techniques slowly.
Well, that is the seven steps finished. If you are working in a development environment that needs this information then I hope that it has been useful. Please let me know your experiences of putting this stuff into practice. If you need any assistance, get in touch – I’ll be happy to help.