What Is “Good” Code Coverage? My Real-World Guide to Stopping Bugs Without Wasting Engineering Time
Every time I run npm run coverage
or phpunit --coverage
, the same question pops up:
“Okay… 74 %. Is that enough?”
The software dev blogosphere shouts “100 % or nothing!” Meanwhile, launchdarkly.com politely reminds me that 100 % executed ≠ 100 % tested.
I’ve spent weeks chasing the shiny metric and more weeks debugging other issues. This is the field-tested middle ground I’ve settled on.
Why 100 % Coverage Is a Mirage
In theory, 100 % line execution means “no hidden bugs.” In practice:
- Diminishing returns: 90 %→95 % often doubles your test suite for single-digit risk reduction.
- False confidence: a test that calls a function without an assertion still counts as covered.
- Business reality: every extra test is time not spent on features your customers asked for.
The aerospace guys can aim for 100 %—it’s life or death. For the rest of us, ~80 % is the 80/20 line. That’s where most projects cluster after ROI calculations. testdevlab.com calls the range 70–90 % for this exact reason.
The Practical Table I Use
Coverage | My Translation | Action |
---|---|---|
100 % | “We’re a library that flies rockets” | Accept the grind. |
90 % + | “Library that lots of money depends on” | High-priority module only. |
80 % | Ship it, monitor, then iterate. | |
60–70 % | Merge gate—fail the PR if new code dips you under. | |
< 50 % | Weekend of tech debt—pivot to critical paths first. |
I stole these numbers from Atlassian’s internal guide: 60 % “acceptable,” 75 % “commendable,” 90 % “exemplary.” Works in every retro.
How I Hit 80 % Without Crying (TypeScript playbook)
- Jest + Istanbul out of the box
- Coverage gate in CI
injest.config.js
I add:coverageThreshold: { global: 80, '**/src/core/**': 90 }
- Target the user hot paths, not the Redux boilerplate logger.
How I Hit 80 % in Laravel (PHP playbook)
- Install PCOV for speed on dev, Xdebug for branch data in CI.
- PHPUnit + these defaults in
phpunit.xml
:<filter> <whitelist processUncoveredFiles="true"> <directory suffix=".php">./src</directory> </whitelist> </filter>
- Mutation score > line count via Infection—that’s how I spot “covered but not really tested” lines.
4 Rules My Team Lives By
- New code = tests. Diff coverage ≥ 90 % before merge.
- Refactor first, test second. Untestable code is already debt.
- Fail the build, not the humans. Lower gate by 5 % every year rather than breaking teams with red dashboards.
- Measure bugs in production—if coverage is 85 % but incidents spike, coverage isn’t the culprit; assertions are.
TL;DR (for execs and recruiters too)
Don’t ask me for a “magic number.” Ask:
Which parts of the product can’t break?
Cover those to 90 %. Give the rest healthy smoke tests. Use code coverage as a spotlight, not a finish line, and trust the bugs you catch, not the numbers you boast.
Let the coverage dashboard be green—your customers will never see it, but their error bar will stay empty.
— End of rant, back to the editor.
Comments