Chapter 05
Tests first, so AI output is checked
Using tests as the specification and the judge: writing the first test yourself, spotting tests that cannot fail, listing edge cases and giving the agent a check it must pass.
Tests as the spec
Also called executable specification, acceptance test
- What
- Writing down the expected behaviour as tests before the code exists, so "done" means the tests pass rather than "the tool said it is done".
- Why
- A test is a check the agent can run by itself. Without one, you are the only test, and you will miss things.
Watch out
Asking the tool to write the code and the tests together, so the tests describe whatever the code happens to do.
Red, green, refactor
Also called TDD, test-driven development
- What
- The test-driven loop: write a failing test (red), write the smallest code that passes it (green), then clean up with the tests still passing (refactor).
- Why
- Seeing the test fail first proves it can fail. With an agent, you or the agent watch red turn green, which is real evidence the change works.
# 1. Red: write the test, run it, see it fail
npm test -- rate-limit.test.ts
# 2. Green: ask the tool for the smallest change
# that makes this test pass; run it again
# 3. Refactor: tidy up, tests still green
npm testWrite the first test yourself
- What
- Writing at least the first, most important test by hand, then letting the tool suggest more cases that you review.
- Why
- The first test is where you decide what the code should do. That decision is the engineering; the rest is typing.
Watch out
Accepting fifty generated tests you never read, most of which check the same happy path.
Tests that cannot fail
Also called tautological test, over-mocking, snapshot abuse
- What
- Tests that pass whatever the code does: asserting that a mock was called with what you gave it, snapshotting output nobody checks, or no assertions at all.
- Why
- AI-generated tests often look thorough and test nothing. Break the code on purpose; if no test fails, the tests are decoration.
- Example
- Change
>to>=in the function under test and rerun. If every test still passes, the boundary is not tested.
Edge case list
Also called boundary values, corner cases
- What
- A list of the inputs most likely to break code: empty, one item, very large, negative, zero, null or missing, duplicates, unicode, time zones, concurrent calls and bad permissions.
- Why
- Models write the happy path well and the edges badly. Giving the list up front, or asking the tool for one and adding to it, closes the gap.
Watch out
Letting the tool decide which edge cases matter for your business rules.
Give the agent a check to run
Also called verification, feedback loop, definition of done
- What
- Telling the agent exactly which command proves the work, the tests, type checker, linter or build, and asking it to run it and show you the output.
- Why
- An agent stops when the work looks done. With a pass-or-fail check it can iterate by itself, and you review evidence instead of claims.
Write a failing test for the timeout case first,
then fix it. Run npm test and npx tsc --noEmit and
paste the output. Do not stop until both pass.Watch out
Believing "all tests pass" without seeing the output: ask for the command and its result.
Do not let it edit tests to pass
Also called test tampering, weakened assertion
- What
- A rule that the agent may not change, skip or delete existing tests to make its change pass, unless you explicitly agree the test was wrong.
- Why
- The easiest way for an agent to reach green is to change the test. A rule in your instructions file and a look at test diffs stop it.
# In your instructions file:
- Never modify, skip or delete existing tests to
make a change pass. If a test looks wrong, stop
and explain why instead.Mutation testing
Also called mutants, Stryker, mutmut, PIT
- What
- A tool makes small deliberate bugs in your code, such as flipping a condition, and reruns the tests. A mutant that survives shows a behaviour no test checks.
- Why
- It measures whether tests actually catch bugs, which coverage cannot. It is a strong check on AI-written test suites.
Watch out
Chasing a perfect score: focus on surviving mutants in code that matters.