Yeda AI Tips · #077

Español

A Test That Passes Against Empty Code Tests Nothing

Would your tests still pass if you deleted the production code? Then they are testing nothing. AI assistants write tests fast — dozens in a minute — and a green suite feels like safety. But green only means "no assertion failed." A test that can't fail against an empty implementation is a test that can't catch the bug that empty implementation represents. It's theater.

The false-green problem

Line coverage tells you which code your tests executed, not whether they would notice a fault in it. The PIT project puts it bluntly: "Traditional test coverage measures only which code is executed by your tests. It does not check that your tests are actually able to detect faults in the executed code." A test can walk every branch, assert something vacuous like assert.ok(true), and report 100% coverage while verifying nothing.

AI-generated tests make this worse, not because the model is careless, but because it optimizes for a passing suite. If the fastest way to green is a tautology — asserting the mock was called with the value the test itself set up, or catching-and-ignoring the exception under test — you'll get a tautology. You asked for tests; you got a green checkmark.

The five-minute audit

Prove your tests can fail. Pick the module the AI just "covered" and break it on purpose:

# 1. Gut the implementation (stub every function to return nothing)
# 2. Rerun the suite
pytest tests/test_orders.py

# Real tests: go red immediately.
# Theater: still green. Delete or rewrite them.

Stub the function body to return None (or pass, or throw new Error()), rerun, and sort tests into two piles. Red means the test earns its keep. Green means it never depended on the behavior at all. This is the manual version of mutation testing, and it takes five minutes per module.

Smells that predict a fake green

SymptomWhat it usually means
assert.ok(true) / assertTrue(True)Placeholder that can never fail
Test asserts the mock returned what the mock was told to returnTests the mock, not the code
try/catch that swallows the failure pathAssertion never reached
Snapshot updated every time it failsTest ratifies changes, doesn't check them
Bug fixed last week, no new red-then-green testRegression can silently return

That last row is the cheapest habit with the biggest payoff: every bug fix ships with a test that failed before the fix and passes after. If you never saw it red, you don't know it works.

Automate it: mutation testing

The delete-the-code trick, industrialized. Mutation tools seed small faults — flip < to <=, add 1 to a literal, swap break and continue — then run your suite. If tests fail, the mutant is killed; if they pass, it survived, and a survivor marks a spot where a real bug would sail through.

This isn't academic. Google wired mutation testing into mandatory code review: its system has been used by ~6,000 engineers, surfacing surviving mutants on the diffs they author and review.

Power moves

Resources

Make tests earn their green. This article pairs with reel #077 of the Yeda AI Tips series — short, source-verified tips for developers building with AI.

Talk to us · More tips · Leer en español