It’s a classic example of Goodhart’s Law in action. Code coverage metrics only measure what percentage of code the test suite causes to run. But it’s very, very easy to write tests that run code without actually confirming that it produces correct output for all possible inputs. And it’s very, very easy to assume that a module with 90+% code coverage also has 90+% behavior coverage, and then become complacent about reviewing the suite for proper behavior coverage.
But most developers don’t have the mathematical sophistication nor the time.
It’s not that unit testing is useless. Just good to know what their limitations are and to plan your testing strategy accordingly.
Tools like QuickCheck and Hypothesis are an interesting middle ground, though. I strongly prefer them over standard-issue unit testing for verifying algorithm implementations.
Although proof techniques such as proof repair have come a long way, it’s still impractical for a lot of scenarios.
TLA+ is great for systems design and such. Quick check style tests are awesome and a very low bar to clear from unit tests.
It already is, ive banned unit tests via ci checks from our codebases, they were not particularly useful before LLMs and now they are a net negative.
We require int and some e2es and that does all that units do and more.
Playwright e2e tests are harder to maintain than pytest code, so I wrote a test just for that one case, and while I was at it, a few other input strings that seemed like they could be problems.
If the function had no test coverage at all, I probably would have tried to get it with an integration test, because that would mean the callers also weren't getting tested.
Its gotten so bad I decided to throw the baby out with the bathwater so to speak and focus on the high value places instead of trying adjudicate every individual usage
I like having both. Unit tests are a decent indicator for local development. Fast, quick to iterate on. Integration tests are slow as molasses and I can’t iterate with them when it takes 20 minutes to setup the suite and run everything. Too slow. But still useful as you say.