AI-Generated Tests Can Miss the Same Bugs as AI-Generated Code
AI coding assistants have become part of the daily workflow for many developers. One common use is generating unit tests, which can save time on repetitive work. That convenience comes with a risk: if the same assistant writes both the implementation and the tests, it may carry the same mistaken assumption into both.
Consider a developer who asks an AI assistant to add a discount for orders totaling $100 or more. The assistant writes a function that applies the discount only when the total is greater than $100, then generates tests for its own implementation. Those tests cover an order below the threshold and another above it, and both pass.
The missing case is an order totaling exactly $100. A boundary test could expose the mistake, but it could also preserve the bug if the assistant derives the expected result from the faulty code. The test suite passes while the original requirement remains unmet.
Tests Need a Source of Truth
Every assertion needs a reason for expecting one result rather than another. That reason may come from a specification, documented example, independently verified calculation, or established business rule. When an assistant receives only an implementation and the instruction “write tests for this function,” it may infer the expected behavior from the code. That can be useful when the goal is to document current behavior or detect later changes. It becomes risky when the implementation is wrong.
A 2024 study of tools including CoverAgent and CoverUp examined buggy, human-written Python programs, primarily from student assignments. The researchers found cases in which generated tests treated faulty behavior as correct. The evaluated workflows could also discard tests that exposed bugs. Those results apply to the versions, configurations, and examples studied; they do not show that every AI testing system behaves the same way.
The same basic problem can occur when AI generates both the implementation and the tests. One mistaken interpretation may shape both outputs. Human developers can make the same error when they carry one assumption into the code and its test suite.
Passing Tests Can Still Leave Gaps
A passing test means that the checks executed during that run did not report a failure. It says nothing about inputs that were never tried or requirements that were never asserted. In the discount example, testing $80 and $120 leaves the boundary unresolved. Testing $100 will not help if the expected result was copied from the faulty comparison.
Coverage reports have similar limits. Line coverage shows which executable lines ran, while branch coverage shows which branches were exercised. Neither confirms that the assertions match the intended behavior. Google’s testing guidance warns that covered code may still contain untested edge cases or inadequate checks.
Reviewers therefore need to look beyond the number of tests and the coverage percentage. For any important assertion, someone should be able to explain where the expected result came from.
Start With the Requirement
One practical approach is to define important examples before generating the implementation. For the discount rule, the team could record three cases:
$99.99 receives no discount.
$100 receives the discount.
$100.01 receives the discount.
These examples make the boundary explicit and give the test suite expectations that do not come from the generated function.
An AI assistant can convert those examples into executable tests and point out unanswered questions. Does shipping count toward the threshold? What happens after a refund? Which currency and rounding rules apply? Someone responsible for the feature still has to resolve those decisions.
Using a separate conversation or another model to write the tests may provide a different perspective, but independence alone is not enough. A fresh session that sees only the implementation can make the same inference. The test writer still needs access to the requirements.
When a generated test fails, developers should investigate the disagreement. The problem may be in the implementation, the test, the setup, or the requirement itself. Changing the expected value just to make the suite pass can hide evidence of a real defect.
Can the Tests Detect Wrong Behavior?
Mutation testing offers another way to examine a test suite. It makes small changes to the code, such as altering a comparison operator or removing a condition, and checks whether the tests fail. Google has documented using mutation testing to surface weaknesses during code review.
A mutation that survives can point to a missing or ineffective test, although not every survivor represents a meaningful problem. Some mutations preserve observable behavior or change details that do not warrant their own test. A suite may also catch many mutations while enforcing the wrong expectations. Mutation testing cannot prove that the code satisfies its requirements.
For teams using AI coding tools, two questions keep the review grounded: What mistake would this test catch, and where did its expected result come from? Clear answers connect passing tests to the behavior the software actually needs.
