Recently, the profile of unit testing has risen dramatically. In the 1990s and early 2000s, it was a practice that seemed to languish. As is often the case when people adopt a new technology back then, organizations were moving from structured design toward object-oriented design they place all their focus on getting the essentials right and discard practices that don't seem to fit neatly into the new picture. And so they neglected unit testing.
But if we've learned anything over the past 10 years, it is that unit testing is an essential discipline. Tests help us better reason about our code, and they form a regression bedrock that makes refactoring and feature addition much easier. There is, however, a very subtle effect of unit testing that few people discuss. There seems to be an eerily consistent connection between testability at the unit level and good design. Almost uniformly, code that is hard to test has design problems. When you fix the design problems, it becomes easy to test.
Let's take a look at an example.
Figure 1: A typical class.
In Figure 1, we have a class that seems to have decent structure. There is one public method,
evaluate(), which is the user's point of contact with the class. It delegates its work to a series of private methods. Overtly, there is nothing wrong with this class
RuleEvaluator does the job we've intended it to. Now, how should we write unit tests for this class? We should be able to instantiate it, call
evaluate() with various arguments, and check the results. But suppose we wanted to test
getNextToken method is private. Theoretically, we should be able write tests for
evaluate that exercise
getNextToken(), but sometimes it is difficult to engineer the inputs we'd want to test a deeply called method specifically. And, if we go down this route, the tests we write might be indirect and not very self-explanatory.
People often run into this problem and think that it is just a case of testing being difficult work. But let's look again.