Test-driven development

Programmer and author Dave Johnson shared an anecdote on his weblog last year about what happened when his 5-year-old son walked up behind him while he was coding. "He saw the JUnit green bar on the screen," Johnson reports, "and said 'Dad, you did good.'" There's more to this touching father-and-son moment than meets the eye. The idea that software development can proceed by tackling a sequence of small tasks -- the successful completion of which is evident even to a child -- is fueling a groundswell of interest in the so-called "xUnit" testing frameworks (see sidebar) and in a companion work style called "test first" or "test driven." [Full story at InfoWorld.com.]

For this story I also interviewed Ward Cunningham and Brian Marick. Both of these conversations were fascinating; here are some outtakes that didn't fit into the article.

Ward on the relationship of QA and test-first development:
If you're the head of QA, and you hear that your developers are working test-first, you should think, "Good for them, now we can focus on the truly diabolical tests instead of working on these dead-on-arrival problems."
Ward on doing only what is declared:
When somebody says this is test-first code, you believe that it's going to be more robust than otherwise. And if you do run into a limitation, it's more likely that you can get past it. Test-first means that it's clear what the code does, and that what it does has been tested, but also that the code doesn't devote a lot of effort to doing things that aren't declared. There is not a lot of cruft lying around in there that's going to prevent you from getting what you want. That's part of the whole extreme programming promise: if you change your mind and ask for something new, it's not an exorbitant penalty for not asking up front.
Ward on the inevitability of test-first:
The idea is so unarguable that everybody who ships software has got to be doing some form of it, they've discovered it themselves. They might not be doing it with the aid of software. Really, test-first is just be clear about what you want, write it, and then see if that's what you got. Although when you get the computer to do the checking, you can make your work easier.
Ward on using FIT:
We had 50 people on the project, 10 were business analysts. When we introduced this FIT style, we told them they could use spreadsheets but they had to work out the test cases. Their first response was: "This is trivial, I can't believe you can't do it." The woman who wrote the first one thought it would take few minutes, and it took a day. As she began writing out the details, she wanted them to be right. She told me that to her surprise, people started lining up outside her door when they heard she was working on the [test-case] spreadsheet. Over the months they did this, as you got from simple to harder, the spreadsheets and test cases got awfully intricate. They had a team of five or six who accepted the responsibility, on an iteration basis, of being prepared to explain what was required in the next iteration, and to have detailed spreadsheets that worked through those cases. It was a huge amount of work. They really felt they had taken on a significant part of the job -- and they had. "This isn't fair, is it?" they'd ask. I'd say: "Think about what you're doing when you do this, would you rather have the developers do it?" They'd say: "The developers should be smarter." I'd say: "They're getting smarter, but they're also worrying about EJB and all that junk." In the end, the business analysts became totally engaged. They didn't like all this work, they wished there was an easier way. But it sure beat writing docs and then bitching about nobody reading them.
Brian on completeness and sufficiency:
When we talk about how testing can drive development, it tends to embroil logically-minded people in pointless arguments of the following sort. The requirements document is a bunch of abstract statements that describe what the program should do for all possible inputs. All the test does is say, for this input, you should get this output. So if the program passes 100 tests, how do you know it's what you really want? What's becoming true, I think, is that we're trying to figure out how to write tests sufficient to cause the programmer to write the right program, even if logically the tests are just a bunch of examples.
Brian on incrementalism:
This whole notion of incremental discovery is really central. The big difference between the way I used to do test-first programming, and the way I do it now, is that I used to think of writing all the tests up front. That makes it much more like a complete representation of the program. Whereas the XP style is radically different, it's one test at a time. That makes a very big difference. If I were going to emphasize one thing to your audience, it would be that.
Brian on the psychology of test-first development:
When I taught testing back in the early 90s, I had people do tests after they wrote the code. I would say in my class, "this all works better if you do it up front," but I didn't have Kent Beck's forcefulness to say "of course you'll write the tests up front, how could you not?" So when you do it after the fact, it becomes a chore, not a tool that helps the programmer. The key thing for adoptibility of any test technique is that it has to make programmers believe they're they're doing more of, and getting better at, what they want to do most of all, which is write code. If you do the tests up front, they're helping you think through the problem. That's good. Programmers are not happy doing any kind of design documentation up front, and one of the reasons is that there's so much of it you don't get your daily fix of coding. The essential thing about test-first programming that makes it possible is that it's a design technique intimately interwoven with the act of coding. Therefore it's sustainable, it's much less likely to get dropped under pressure, because it's not a separate activity.
Brian on the test-first safety net:
When I'm working on a new feature, I'll go in and deliberately break something in the guts of the program, then run the tests and see which ones fail. It's a form of traceability that is automated. And it's a really powerful feeling -- a switch from the usual feeling that your program is an elaborate house of cards. Now you can pull the card out, see what tumbles down, and then just make it work. It's a way of converting programming from an adrenalin-filled activity to something smooth. It's about about smooth, steady, fast progress.

Former URL: http://weblog.infoworld.com/udell/2003/08/04.html#a765