Minimal

stressed for motivation and achievement

2006-02-12

 

Test-driven development: theory and practice

I hate having to make posts like this. Ah well, here goes...

Following Jack’s recent post on TDD on the Reiver Games blog, I posted a “me too” kind of response here. All this has done is increase people’s perception of me as anti-agile; a badge I wouldn’t ordinarily give myself. Admittedly, it’s all my own fault—in an attempt to provide an alternative viewpoint, I’m painting myself as way too black and white. If you’ll bear with me, I’d like to take the time to explain myself. If not, please skip this post.

[continues inside...]

So... my view of TDD’s benefits and pitfalls:

Benefit #1
Promotes simple (from a client’s p.o.v.) and relatively decoupled code. Often, you end up seeing methods in Intellisense that are so well named and so well encapsulated that use of the class requires no documentation whatsoever. Many of my best class interfaces have been born in a TDD environment. I love them almost like children.
Benefit #2
Automated regression testing: a huge boon. Remember this: the greatest benefit of your unit tests comes from their repeated running, not from the first green light. This is where you really feel the power. Just remember, too, that you may not have been able to cover all bases with the unit tests.
Benefit #3
Supports development in small increments, helping maintain a stable product. Whether you check-in a test at a time or a test fixture at a time, the scope of what you’re doing is helping you stay fairly well focused on a small part of the overall system. Working this way allows you to concentrate all your efforts on that subsystem and so you usually end up checking-in highly robust code. Of course, robustness doesn’t come for free, but staying focused will help you.
Pitfall #1
Waiting to complete one test before starting the next (something I’ve seen and heard espoused by agilists) makes it too easy to forget you’ve missed important test cases. It’s too easy to fall into a sense of being done. This is what Jack wrote about today. In the past, I tried writing further tests down on paper as they came into my head, but by that lacked any forcing mechanism to make sure I addressed them. Adding test titles as comments in my test fixtures suffered the same problem.
The only approach that worked for me was to stub (and fail) each new test case as soon as it popped into my head. Or even to spend 5 minutes before starting a new feature, writing failing stubs for all of the test cases I thought I would need to cover. Unless I had a red light to clear, it was too easy to forget to write the test code. And unless I stubbed the test cases up front, it was too easy to forget I’d ever thought of them. It was frowned upon by some, but if it works for you, JFDI.
Pitfall #2
Despite evangelism claiming otherwise, many unit tests (esp. those in UI code) do not represent time well spent. When I was still developing in a test-driven style at work, I really wanted to be the good agilist, unit-testing even the UI. In hindsight, I held my project up by doing this. I contributed to its eventual failure. I still harbour a deep sense of regret and guilt for this. And, for that matter, anger and bitterness towards those who insisted I should be writing those tests. I really should have listened to my gut. I had a mind of my own, but I’d been browbeaten into ignoring it.
Pitfall #3
Mocking objects is rarely satisfactory. While NMock and its cousins are technically brilliant little libraries, they intrinsically increase the coupling between tests and the production code. This makes large-scale refactorings an absolute f***ing nightmare. I really can’t stress that strongly enough. It’s enough to make you question whether such libraries are really worth their place on this planet.
When working in UI-controlling code (e.g. the presenter in an MVP pattern), in particular, it’s enough to drive you insane. User interfaces, by their nature, almost always involve an iterative design process. Tests that check that values are fed into the UI at the right time are particularly susceptible to changes, especially if you need to switch from a push to a pull model (or vice versa).
Of course, no-one’s forcing you to use mocking. It just feels that you’re damned if you do and damned if you don’t. Mocking can easily end up testing the implementation of otherwise encapsulated algorithms (a bad thing, obviously). Not mocking, however, can end up ruining the usability of your classes by exposing too much state in the interface, purely for the sake of the tests. It’s a shit, isn’t it?

So, how much TDD am I doing at work these days? In a word, none. I’m not doing TDD at all and I’m very rarely writing unit tests. And, in the circumstances, I feel entirely comfortable with it.

My lack of TDD is entirely because my work is 99% UI work and experience tells me not to bother. Were I working on the underlying business layer, you can bet your sweet ass I’d be unit testing. Perhaps not doing TDD, as it’s rare that brand new code is written in that layer (in my project, that is), but I’d certainly be looking to cover existing code with a unit test before meddling with it.

I hope this article (for it’s more than just a regular post!) has set the record straight. I’m not anti TDD. I’m not anti-agile. I’m receptive to anything that works. And, after a couple of years of guilt, I feel completely confident in the validity of my approach. Whether you think I’m right or not is up to you. Just promise me you’ll only do what works for you.


Comments:
I reckon refactoring under unit tests should be down as both a benefit (you know you've not broken anything) and a pitfall (unless your God's gift to unit testing you'll probably have to change your unit tests too - twice as much effort, plus there's the chance you might break the tests in the process). I agree that unit testing UI can often be an absolute nightmare and take way too long. And I think if you're good at it, it's essential in backend code.
 
Post a Comment



<< Home

Archives

April 2002   May 2002   June 2002   July 2002   August 2002   September 2002   October 2002   November 2002   December 2002   January 2003   February 2003   March 2003   April 2003   May 2003   June 2003   July 2003   August 2003   September 2003   October 2003   November 2003   December 2003   January 2004   February 2004   March 2004   May 2004   June 2004   July 2004   August 2004   September 2004   October 2004   November 2004   December 2004   January 2005   February 2005   March 2005   April 2005   May 2005   June 2005   July 2005   August 2005   September 2005   October 2005   November 2005   December 2005   January 2006   February 2006   March 2006   April 2006   May 2006   June 2006   July 2006   August 2006   September 2006   October 2006   November 2006   December 2006   January 2007   February 2007  

This page is powered by Blogger. Isn't yours?