Earlier this year, I did a review of Pragmatic Unit Testing in C# with NUnit. As I said then, the book provides an introduction to NUnit and to unit testing, but doesn’t go into much depth for either. Looking for more detailed information, I found The Art of Unit Testing.
This is a book that is low on theory and high on hands-on practice. Roy wastes no time in showing code and explaining what it does, and succinctly so.
The book is divided in four parts, ranging from an introduction to unit testing, to coverage of core concepts, to discussions on writing and managing unit test code, to making use of unit tests in the business.
The first part starts with an introduction to unit testing: the what, why, and how. From there, Roy shows how to write unit tests without using a framework such as NUnit; this serves to solidify the concept of unit tests. With this foundation laid, Roy then switches to using NUnit throughout the rest of the book.
Part two is centred around stubs, mocks, and mock frameworks. Roy explains each in detail; he specifically compares and contrasts stubs and mocks, explaining how each is useful in certain situations. I found this information very revealing, as I hadn’t had any idea as to their differences. Following this revelation is a description of what mock frameworks are, and how they are useful to ease the unit testing process. There are a number of such frameworks available; Roy lists a few of them, indicating their good points and their bad points. Rhino.Mocks seems to be the dominant mock framework in the .NET community, and as such is used in most of the mocking examples.
Part three is about organizing unit test code. Even though unit tests are not production code, their organization and quality matters just as much as the production code. Roy shows ways that test classes and methods can be organized and named. On that latter point, I have taken up the suggested practice of naming my test methods as
MethodName_WithConditions_ExpectedResult. This one change is making my unit tests more readable already! Also of interest was the hierarchical organization of test classes for a matching hierarchy of classes under test, as well as the use of test-assisting utility classes and methods. The following chapter is very illuminating; it discusses the concept that tests must be trustworthy, readable, and maintainable. This is food for thought for me, and is goading me to review my existing test code for those qualities, or lack thereof. This chapter alone makes the book worth buying.
The fourth and final section serves to wrap up the book. It provides advice on integrating the unit testing process into a business workflow, and on testing legacy code. This latter chapter was especially interesting for me, as I have what is considered legacy code that needs to be tested. Especially interesting was the advice on choosing what to get under test first, based on value and risk. There are suggestions to use certain tools, including NDepend, ReSharper, and Simian, to help the process.
There are two appendices: one about designing for testability, and one that lists various useful tools and frameworks for writing code and unit tests. They are both useful collections of information, but are tangential enough to the main subject to be relegated to appendices. There is of course a book index at the end.
There is an extra supplement inside the back cover: a list of steps to take when reviewing test code. Each step has a page number next to it, directing the reader to the relevant section in the book covering that given subject in detail. This will be a useful quick reference. There is an online version that goes into more detail.
This book is a good complement to Michael Feathers’ book, Working Effectively with Legacy Code, which I reviewed a year ago. Art of Unit Testing is primarily about writing unit tests, while Working Effectively with Legacy Code focuses on refactoring code to make it testable. In this book, there is actually a reference in the final chapter to the Legacy Code book, along with an imperative:
“It’s worth its weight in gold. Go get it.”
If you are considering getting Art of Unit Testing, you should also get Working Effectively with Legacy Code, as they complement each other.
Technical books have a tendency to be overly long, dry, and packed with nitty-gritty details. Not so with this one. Roy gives good examples, and provides clear and concise explanations. That said, the subject material is a little heavy – no fault of the book – and may take some while to sink in. If you have some experience with unit testing and want to go further, this book is a worthwhile read.
The only downside I found is that there is scant mention of other forms of testing – integration, system, acceptance, etc. On one hand, it would be useful to at least have some comparison between the various types of testing, if not detailed coverage. On the other hand, the book is titled The Art of Unit Testing, and so is focused on unit testing. That is probably a good thing, as it keeps the book smaller and more tightly scoped. So this is probably a non-issue. Integration tests do get mentioned early in the book to differentiate them from unit tests, but they don’t seem to be discussed further. Granted, integration or system testing are probably more deserving of their own books for detailed coverage anyway.
Overall, this book covers unit testing techniques in depth, and is well worth keeping handy when writing unit tests. Examples shown are in C#, written for .NET, and use the NUnit and Rhino.Mocks frameworks, but the book is less about the tools and more about the processes that they enable. This book is thought-provoking and, unless you are already a subject guru, will help you in writing better test code. I can feel the late nights coming already.