Finished test-driven development: A Practical Guide by David Astels. The book contains three parts. Part 1 introduces the reader to test-driven development. Part 2 discusses various tools and techniques for doing TDD. Part 3 presents an extended example by going through the test-driven development of a movie rating application.
Test-driven development builds on the principle that developers should write tests before they write code. The tests determine the code that needs to be written. As a side effect, this results in a suite of programmer tests. However, the book stresses that TDD primarily exists as a development methodology, not a testing methodology. The test suite produced by this methodology should not be considered a replacement for through testing by those who have testing as their primary goal.
While reading the book, I started using TDD in my daily development. It works well for me. TDD helps me in the following ways. It solves the problem of the blank page. Sometimes I know the things I want to do to accomplish the task, but I do not know where to start. Sometimes I do not know what I need to do. TDD helps in both of these cases by recommending that I start with the simplest test and work forward from there. The first test may seem trivial, but I have found that, in practice, it tends to take a fair amount of work because getting that first test to compile and run requires setting up classes, wiring things up (if working in existing code), etc.
The TDD work cycle consists of: write tests (i.e., plan), write the minimal code necessary to make the test pass, and then refactor. Each iteration of this work cycle takes minutes. With such a short work cycle, I stay focused on the task at hand rather than getting distracted by other things I could do. (e.g., refactoring a method while I am adding new functionality to it or adding two types of functionality at a time). When I stay focused on one thing at a time, I am less likely to end up in a situation where I spend 30 minutes making changes, go to compile, and find that the code will not compile or the tests fail for non-obvious reasons. In a world of tight focus failures occur but causes appear more readily.
This work cycle also encourages frequent refactoring, even though it discourages refactoring while adding new functionality. Since adopting this work cycle, I have found that I do a better job refactoring when I do it in small, frequent bursts rather than saving it up until the end. The same holds for writing comments and doing other tasks. When I have the discipline to clean my code up regularly, I do a better job than when I leave clean up for the end. Clean-up works best when the full meaning the related code is fresh in my mind. Plus, lots of code clean-up clumped together is boring.
This book showed its strength in the general overview of test driven development. The section on specific technologies proved to be less useful, mostly due to the fact that the discussion of the technologies I use contained somewhat outdated material, and I assume that other discussions possessed similar short comings. Of course, that does not surprise me given that the book came out in 2003.
The third part of the book really makes it "a practical guide". It contains an extended example showing the test-driven development of a movie rating application. I appreciated the level of detail that went into the example, but I also found myself unable to read all of it. The author did his best to keep each chapter in part 3 fresh, but eventually the example got boring. I ended up skimming most of these chapters. These chapters made up nearly half the book, so shortcomings in them significantly impact the overall quality of the book. I feel the book would have been significantly better if the bulk of these examples had been moved into an appendix (even given the length of the example, that would have been fairly practical because an appendix would have required less narrative to string the examples together).
Beyond that, the main thing I would have liked to see covered in this book is a discussion of test-driven development in a legacy system. Legacy systems often lack comprehensive tests, and they often lack the features that make testing easy. Test-driven development in such a system takes a lot more effort than in a new project. A discussion of factors that go into applying a test-driven development process to such a code base would have been a valuable addition to this book.
test-driven development: A Practical Guide provides a good introduction to test-driven development. It contains many useful insights and practical tips. However, I suspect that you can find more focused, up-to-date introductions to the topic than the one found in this book.