Why I stopped chasing 100% coverage
1 min
Coverage is a map, not the territory. Where I now spend the testing budget instead — and the one number I still watch closely.
Chasing the last few percent of coverage mostly buys tests for code that can’t meaningfully fail — getters, trivial constructors, error branches that exist only to satisfy a linter. Writing those tests felt productive and taught the codebase nothing. The bugs that actually reached production were almost never in the untested 4%; they were in the interactions between well-tested pieces that nobody had thought to test together.
What I spend the budget on now: the boundaries. Every place data crosses a trust line — a request handler, a database write, a third-party API response — gets a test that exercises the shape of a real payload, including the malformed ones. That’s a small fraction of the codebase by line count and a large fraction of where incidents actually start.
The one number I still watch closely is mutation score on that boundary code specifically, not coverage. A test suite can hit 100% line coverage while asserting nothing meaningful; mutation testing catches that by checking whether a deliberately broken version of the code actually fails a test. If a mutant survives in boundary code, that’s the test worth writing next.