Wednesday, December 9, 2009

Some test-driven-development notes

A couple of random points that might be of interest:

Code coverage tools

if ( rare-condition ) {
-is this code tested?-
}

If you actually followed test-first, then the code in the rare if is definitely tested, because if there isn't failing test case for the rare condition, then there is no reason for the code or the test to exist.

Another objection could be that people won't follow the techniques. I haven't found this to be a big or recurring practical problem so far,
and agile techniqes tend to be empirically driven. If you suspect that this is a problem you are seeing in your environment, running a code-coverage tool to put some data behind your suspicion may be a good idea.

Test before or test after?

Note that the solution to the code-coverage question above does not
work if tests are written after the fact: in this case, the rare-case is likely not to be covered because it was written without being forced by a failing unit test.

Many if not most of the benefits of TDD are related to the way they shape the
design of the code, all of these benefits obviously don't accrue
if you've already designed or even written the code. In fact, if you ask the XP
folks about it, they will tell you that TDD is not for ensuring
quality, it is exclusively for helping with coding and design.

For example, figuring out
how to test something will force you to come to a clarity about
what the code is supposed to do that just writing the code usually
does not.

Knowing that your tests cover your code (see above) allows you to do extremely
radical refactorings at any point in the development process. The
ability to refactor at any time in turn allows you to keep your
initial designs simple without coding for anticipated changes. Not
coding for anticipated changes that may not occur or may occur
differently than you expect in turns allows you to move more quickly,
which more than pays for the expense of the tests.

Furthermore, the tests force you to think how you can call the
functionality you are about to implement, which means it shapes
architecture towards simplicity, high cohesion and low-coupling.

Generating tests

Auto-generating tests for existing methods is a means of subverting the test-driven approach: there will be the appearance of testing, but with
virtually none of the benefits. It is probably worse than not having
tests, because in the latter case you at least know that you're not
covered.

Is it a good way of starting with unit test coverage for legacy code? No. See the C2 wiki entry for a good explanation of how to approach this case. In short, start refactoring and adding unit tests when you actually need to touch the code,
be it for new features or to fix defects that are scheduled to be fixed.