Unit tests are not for validation

A common, but mistaken view of unit tests is that their main function is to validate code. One of the most common arguments used against the practice is that you can’t prove your code works with unit tests. This is of course a truism of all testing, not just unit tests, but I believe also reflects a misunderstanding of the real advantages provided by unit testing: behavior stability.

The advantage of unit testing comes not when you run your tests, see a green light, and assume you’ve written the right thing. This is actually a rather silly assumption to make, and if you run into a developer that assumes green light means “it works” you should correct them at the earliest opportunity. The great advantage of unit testing comes when you want to change the code without changing behavior.

Why would you ever bother to change code without changing behavior though? Shouldn’t you leave code alone unless you intend to fix a bug or add a feature?

Yes. You should leave code alone unless you intend to alter its behavior. This doesn’t mean though that the only reason to change code is to change behavior. More often than not, when you need to change behavior you’ll find that the architecture doesn’t readily support it as is. In the quest to add a feature or fix a bug you may find that you need to alter the structure of a component or components. This is called refactoring and it is here that unit testing really lends a hand because it allows you to restructure your program and be fairly sure that you’re not altering behavior–at least nothing the original author intended.

Furthermore, even if you don’t restructure the program to fix a bug or add a feature, you still don’t want to change things in ways the rest of the program doesn’t expect and possibly cannot handle. Fixing bugs can very often introduce other bugs, and adding features can quite often break existing behavior. If you don’t have unit tests you can’t check these things until your product is in QA, which in some firms doesn’t happen right away and is certainly less speedy a feedback than running tests before you ever even check anything in.

So that is how you should think about unit tests. Don’t think of them as validators checking that your code is doing the right thing. Think of them as a method to document what your code does in such a way that anyone can check that it continues to do the same thing after it’s changed.