Now I'm going back to it I'm starting to see how it can be possible, and it looks like being genuinely useful and should stop (or at least quickly highlight) lots of bugs before they become an issue. On the other hand it's almost certainly harder than non-TDD and seems to require a more diciplined approach to code. I'm going to be interested in just how far everyone's doing it, as I suspect it'll mostly be a token effort with a few unit tests here and there rather than 'proper' TDD. Personally I'm planning to take it as far as possible with my own code (the nature of the code means I can take certain liberties that others can't) but I suspect I'll end up skipping it when deadlines start looming.
As a quick test I decided to try adding a few tests to my personal projects, starting with my animation tool. Since I want something easy to start with I pick a nice, small-ish class which already has minimal dependancies - the KeyframeBone class.
The KeyframeBone doesn't actually depend on anything - it only references other KeyframeBones to form a tree structure, and uses ArrayList and Object from the Java API. So I knock up a quick test (using Eclipse's JUnit intergration):
public void testCalcWorldPos()
KeyframeBone testBone = new KeyframeBone(null, 10, 20);
// Identity transform (no translate or rotation)
testBone.calculateWorldPositions(0, 0, 0);
assertEquals(testBone.getWorldX(), 10, EPSILON);
assertEquals(testBone.getWorldY(), 20, EPSILON);
JUnit was a piece of cake to setup, and other than the test itself the only bit of boilerplate code is sticking the whole thing into a class inheriting from TestCase. Run the test and everything is good.
Wait, test failed? WTF? But this code hasn't been changed in ages! I've been using it for ages too, I know it works!
Except it doesn't.
Stepping though reveals that the rotation code is doing something screwy and everything gets mirrored on the x axis. Somehow this has been broken since it was first written, and has managed to remain dormant for over a year before I spotted it just now. I can only assume it 'works' because I never actually inspect the numbers manually. Worse, I've a sneaking suspicion that I'll find a similar bug in the mouse click handling - one mirroring the values as it goes in, the other as it goes out - so it all appears on the surface to be working fine.
I'm beginning to see the light now, and how unit tests can catch this sort of thing early. But it's a scary kind of light, because now I'm thinking just how much code I've got thats not covered by unit tests, and wondering how many bugs I'm going to uncover when I start adding them...