I was reminded yesterday that there are still many people out there who still don’t really understand the purpose of unit testing.
A funny shift happened in the last 5 or so years.
About 5 years ago, when I would suggest TDD or just doing some unit testing when creating code, I would get horrible responses back. Many developers and managers didn’t understand why unit testing was important and thought it was just extra work.
More recently when I have heard people talking about unit testing, almost everyone agrees unit testing is a good idea, but not because they understand why, but because it is now expected in the programming world.
Progress without understanding is just moving forward in a random direction.
Getting back to the basics
Unit testing isn’t testing at all.
Unit testing, especially test driven development, is a design or implementation activity, not a testing activity.
You get two primary benefits from unit testing, with a majority of the value going to the first:
- Guides your design to be loosely coupled and well fleshed out. If doing test driven development, it limits the code you write to only what is needed and helps you to evolve that code in small steps.
- Provides fast automated regression for refactors and small changes to the code.
I’m not saying that is all the value, but those are the two most important.
(Unit testing also gives you living documentation about how small pieces of the system work.)
Unit testing forces you to actually use the class you are creating and punishes you if the class is too big and contains more than one responsibility.
By that pain, you change your design to be more cohesive and loosely coupled.
You consider more scenarios your class could face and determine the behavior of those, which drives the design and completeness of your class.
When you are done, you end up with some automated tests that do not ensure the system works correctly, but do ensure the functionality does not change.
In reality, the majority of the value is in the act of creating the unit tests when creating the code. This is one of the main reasons why it makes no sense to go back and write unit tests after the code has been written.
The flawed thinking
Here are some bad no-nos that indicate you don’t understand unit testing:
- You are writing the unit tests after the code is written and not during or before.
- You are having someone else write unit tests for your code.
- You are writing integration or system tests and calling them unit tests just because they directly call methods in the code.
- You are having QA write unit tests because they are tests after all.
Unit tests are a lot of work to write. If you wanted to cover an entire system with unit tests with a decent amount of code coverage, you are talking about a huge amount of work.
If you are not getting the first primary value of unit testing, improving your design, you are wasting a crap load of time and money writing unit tests.
Honestly, what do you think taking a bunch of code you already wrote or someone else did and having everyone start writing unit tests for it will do?
Do you think it will improve the code magically just by adding unit tests without even changing the code?
Perhaps you think the value of having regression is so high that it will justify this kind of a cost?
I’m not saying not to add unit tests to legacy code. What I am saying is that when you add unit tests to legacy code, you better be getting your value out of it, because it is hard work and costs many hours.
When you touch legacy code, refactor that code and use the unit tests to guide that refactored design.
Don’t assume unit tests are magic.
Unit tests are like guidelines that help you cut straight. It is ridiculous to try and add guidelines to a word-working project after you have already cut the wood.