I've seen this problem with humans even back at university when it was the lecturer's own example attempting to illustrate the value of formal methods and verification.
I would say the solution is neither "get humans to do it" nor "do it before writing code", but rather "get multiple different minds involved to check each other's blind spots, and no matter how many AI models you throw at it they only count as one mind even when they're from different providers". Human tests and AI code, AI tests and human code, having humans do code reviews of AI code or vice-versa, all good. Two different humans usually have different blind spots, though even then I've seen some humans bully their way into being the only voice in the room with the full support of their boss, not that AI would help with that.
> "get multiple different minds involved to check each other's blind spots
This is actually my big gripe about chatbot coding agents. They are trained on human preference and thus they optimize for errors that are in our blind spots.I don't think people take this subtly seriously enough. Unless we have an /objective/ ground truth we end up proxying our optimization. So we don't optimize for code that /is/ correct, we optimize for code that /looks/ correct. It may seem like a subtle difference but it is critical.
The big difference is when they make errors they are errors that are more likely to be difficult for humans to detect.
Good tools should complement tool users. Fill in gaps. But as we've been trying to train agents to replace humans we are not focusing on this distinction. I want my coding agent to make errors that are obvious to me just as I want errors I make to be obvious to it (or for it to be optimized to detect errors I make)
As the sibling comments alluded to, it’s not exclusively an AI problem since multiple people can miss the issue too.
It’s wonderful that AI is an impetus for so many people to finally learn proper engineering principles though!
Yeah, it burns CPU like crazy, but CPU time is dirt cheap right now compared to the cost of an engineer debugging that self-deception in production
I think it happens not at 100% coverage but at, say, 100% MC/DC test coverage. This is what SQLite and avionics software aim for.
*has not been confirmed by a peer-reviewed research.
It's mandated by DO-178C for the highest-level (Level A) avionics software.
Example: if (A && B || C) { ... } else { ... } needs individual tests for A, B, and C.
Test #,A,B,A && B,Outcome taken,Shows independence for
1,True,True,True,if branch,(baseline true)
2,False,True,False,else branch,A (A flips outcome while B fixed at True)
3,True,False,False,else branch,B (B flips outcome while A fixed at True)
Test # A B C Result
1 True True False True
2 False True False False
3 True False False False
4 False True True True- Every branch was "visited". Plain coverage already ensures that. I would actually advocate for 100% branch coverage before 100% line coverage.
- Every part (condition) of a branch clause has taken all possible values. If you have if(enabled && limit > 0), MC/DC requires you to test with enabled, !enabled, limit >0, limit <=0.
- Every change to the condition was shown to somehow change the outcome. (false && limit > 0) would not pass this, a change to the limit would not affect the outcome - the decision is always false. But @zweifuss has a better example.
- And, of course, every possible decision (the outcome of the entire 'enabled && limit > 0') needs to be tested. This is what ensures that every branch is taken for if statements, but also for switch statements that they are exhaustive etc.
MC/DC is usually required for all safety-critical code as per NASA, ESA, automotive (ISO 26262) and industrial (IEC 61508).
I hope you don't have any string inputs, or your test is gonna take a while to run!
But yes, exhaustively testing your code is a bit exhausting ;)
IMO it’s quite boilerplate-y to set this up pre-LLM but probably the ROI is favorable now.
Furthermore, as Uncle Bob has written a lot about, putting effort into structuring your tests well is another area that’s usually under-invested. LLMs often write very repetitive tests, but are happy to DRY out, write factories, etc if you ask them.
Obviously that's not good enough, but I'd much rather have AI tests than poor test coverage.
Btw, you can get a lot further in your tests, if you move away from examples, and towards properties.
https://hypothesis.readthedocs.io/en/latest/ are the docs for one of the best property based testing libraries available in any language.