Why developers can't test their own code
The assumptions that shaped the code shape the testing too. That is not a discipline problem, and no amount of coverage fixes it.
Every engineering team we talk to has already tried the obvious thing. They asked the developers to test more carefully. They added a checklist to the pull request template. They set a coverage threshold in CI and watched it turn green.
Then the same class of bug reached production anyway.
The gap is structural, not lazy
When an engineer tests the feature they just built, they test it the way they built it. The mental model that produced the code is the same model that produces the test cases, so the tests inherit every assumption the implementation made, including the wrong ones.
A developer's tests prove the code does what they thought it should. They cannot prove it does what a user will actually do to it.
This is why the failure is so consistent across teams of very different quality. It is not a question of care or seniority. You cannot find a blind spot by looking harder from the same position. Someone has to stand somewhere else.
What that looks like in a real suite
Look at the tests on any feature written by the person who built it, and they cluster:
- the happy path, end to end
- the one validation error the form was designed around
- the empty state, because it was on the ticket
- whatever broke last time
Now look at what is missing. Nobody wrote a test for the user who double-clicks submit, because the developer knows the button disables itself. Nobody tested the email address with a + in it, because the regex looked fine. Nobody tried it on a slow connection, because it was fast on their machine.
None of those are exotic. They are just outside the model.
Coverage measures the wrong thing
Line coverage tells you which lines ran while the tests executed. It says nothing about which behaviours were checked, and it is trivially satisfied by tests that assert almost nothing.
A suite at 90% coverage written by the feature's author and a suite at 60% written by someone trying to break the feature are not comparable artifacts. The second one finds more bugs. We have never seen it go the other way.
What actually closes it
Three things, roughly in order of how much they buy you:
- Someone who did not write the code writes the test plan. This is the whole of it. Everything else is an optimisation on top.
- Test against the requirement, not the implementation. If the test was derived by reading the diff, it is a description of the diff.
- Keep a written record of what was checked. Not for process theatre, but so that next quarter, when the same area breaks, you know whether it was ever covered.
The first one is the reason outsourced QA works at all, and it is why it does not need to be expensive to be worth it. A second set of eyes is not a luxury tier. It is the mechanism.
If you want to see what that produces in practice, how we work walks through the actual artifacts from real engagements, redacted: the test results, the bug tickets, the investigation notes.
