Do you aim for 80% code coverage? Let me guess which 80% you choose...
Are you one of the many developers that believes that there’s a sweet spot of code coverage?
Usually it’s something like 80%. You may have set up your CI environment to fail your build if it drops below that percentage.
Your team be subject to this CI threshold even though you personally have never given thought to why that threshold exists.
People believe in this threshold because 100% is difficult to achieve. The belief is that reaching for anything beyond 80% takes a great deal of energy for little benefit. Put another way, code coverage is governed by the law of diminishing returns.
I think 100% code coverage is worth aiming for, and here’s one reason why.
The 20% you leave uncovered is probably the 20% that needs it the most.
The notion of Just Enough Coverage and why it doesn’t work
Which 80% do you choose? What 80% is being tested? And what’s in the 20% that isn’t?
There are a couple of obvious choices:
- test the 80% that’s most straightforward / easiest to test
- test only the happy path
Covering the easiest 80%
If you leave the most difficult 20% untested, then you are building a knot of spaghetti code. So you have this 20% of spaghetti code festering in the core of your product.
That in itself is a risk. Spaghetti code has a tendency to grow and grow in a way that well-tested code does not.
The reason for this is simple: when we add on top of covered code, we are very confident about refactoring (pulling out abstractions, keeping the code concise, simplifying, etc). Conversely, we shy away from refactoring code which isn’t covered.
So eventually that 20% becomes a liability, and it becomes harder and harder to get to that 80% as the 20% pushes outwards. Life becomes difficult.
Covering only the happy path
If you’re only writing test coverage for happy path, this suggests that error-handling logic isn’t as well-factored as the rest of your code (assuming, again, that your tested code is in better shape than your untested code).
But unhappy path logic is often more critical to get right than happy path. When errors occur, you need to ensure that they are reported correctly and that the effect on the user is limited. Perhaps the code you write will be alerting monitoring systems that something went wrong, or perhaps it’s placating the customer and letting them know how to deal with the issue. Either way, it’d be a disaster if that code didn’t work.
Not to mention that the happy path is the path you’re most likely to manually test.
So writing automated tests for the unhappy path is arguably more important than writing automated tests for the happy path.
Aiming for 100% coverage is not everyone’s cup of tea. Regardless of whatever lower threshold your CI environment requires for a passing build, aiming for full coverage is a great way to level up as a developer, and a very noble goal.
If you’re interested in this topic and you’re a front-end developer, you may be interested in this talk:
Happy testing! 🙏