This post originated from an RSS feed registered with Agile Buzz
by Keith Ray.
Original Post: The Testing Kitchen Metaphor
Feed Title: MemoRanda
Feed URL: http://homepage.mac.com/1/homepage404ErrorPage.html
Feed Description: Keith Ray's notes to be remembered on agile software development, project management, oo programming, and other topics.
"Testing is like tasting your food while you are cooking - it's part of the fun of cooking - and if you don't taste it as you go along, it will probably taste like crap at the end." -- Kevin Lawrence, in a comment to a blog entry by Ashish Kumar.
One of the other comments said that "junit is great for testing extremely well designed code or extremely simple code, most [real world] code is neither". Of course, Test Driven Development isn't "testing". (See the article TDD Isn't Testing by Jeff Patton.) TDD is a way of developing code driven by one test at a time, and it (usually) turns out to be easier than the normal code-and-debug AND results in well-designed and simple code.
(If you do test-driven coding without refactoring then you will get poorly designed code, but refactoring is a required step in TDD. Not doing refactoring means you're not doing TDD.) Back to my main point.
Sometimes TDD is hard because the existing APIs you're trying to use are poorly-documented, or just hard to test. I had problems doing TDD with AppleEvent programming (on MacOS 9 in C++) for both reasons. This is worse than doing TDD on the "edge" of legacy code because legacy code can be (carefully) refactored, but system calls like the AppleEvent API are basically take-em-or-leave-em.
TDD is a new habit, and new habits can be hard to acquire. The rewards are worth it, in my opinion. One reward in particular is the nearly-complete elimination of stepping through the debugger, which can be so time-consuming. I can write a quick 3-line test asserting what I'm interested in, run ALL the programmer-tests, and get a pass or fail (with helpful output) in less time then it takes to run the software manually and break at the right place with the debugger. TDD doesn't prevent "missing-features" but it does help in finding and fixing bugs almost as soon as you write the buggy code. If a test fails unexpectedly during TDD, it's almost always in the last few lines of code you wrote -- you don't need to spend a lot of time in the debugging tracking down the defect.
Notice that I said "3-line test". A TDD test consists of (1) setting up the context, (2) exercising the method(s) of interest, and (3) asserting the expected outcome. If any of the steps is hard, this is an opportunity to improve the tests and the code (via refactoring) until it is easy. Of course, if a TDD test takes 5 lines, or 10, it's not necessarily an urgent task to refactor.