Skip to content
English
all Engineering playbooks

playbook

Backfill the tests you never wrote

Take a module with no tests, have Claude list the behaviours worth pinning down — including the nasty edge cases — and write a suite that covers them, flagging any latent bugs it finds on the way.

medium ~30 min

when to reach for this

There's a module everyone's afraid to touch because it has no tests. You want to change it, but without a safety net every edit is a gamble. This system turns "untested and scary" into "covered and safe to refactor" — and the act of writing the tests usually surfaces a bug or two that were hiding the whole time.

gather this first

  • The file or module you want covered, open in the repo so Claude reads the real implementation.
  • How you run tests in this project — the command and the framework (vitest, pytest, go test), so the suite fits your setup.
  • Any behaviours you already know matter — the edge cases that have burned you before.

the workflow

  1. List the behaviours before writing a single test

    Don't ask for tests yet. Ask for the inventory of what this code is supposed to do — the happy path and, more importantly, the edges. You'll catch a missing case here.

    you ask
    Read this module. Before writing any tests, list every behaviour worth pinning down — the normal paths and the nasty edge cases (empty input, nulls, boundaries, concurrent calls, error paths). Flag anything that already looks like a latent bug.

    what you get back A checklist of behaviours grouped into happy-path and edge-case, plus a short "this looks suspicious" list — the spec the code never had written down.

    The edge-case list is the valuable part. The happy path you'd have tested anyway; the boundaries are where the bugs live.

  2. Write the suite against that list

    Now turn the inventory into real tests in your framework, named so a future reader knows what broke when one goes red.

    you ask
    Write a test suite covering that list using our test setup. Name each test after the behaviour it pins down, cover the edge cases explicitly, and keep each test focused on one thing. Don't change the module yet.

    what you get back A readable suite where each test maps to a behaviour from step 1 — the edge cases as their own named cases, not buried in one giant test.

  3. Run it and confront the failures

    Some of the new tests may fail against the current code. That's not a bug in the tests — that's the suite earning its keep.

    you ask
    Run the suite. For anything that fails, tell me whether the test is wrong or the code is — don't just "fix" the test to make it pass. If it's a real bug, show me the smallest fix.

    what you get back Either green, or an honest split: "these two failures are real bugs in the module, these are my test mistakes" — with a fix proposed for the real ones, separate from the tests.

    Watch for the tempting anti-pattern: making a failing test pass by weakening the assertion. A test that can't fail protects nothing.

make it your own

  • **Characterization first:** for code you don't fully understand, ask for *characterization tests* that pin the current behaviour exactly as-is — even the quirks — so you can refactor safely before deciding what's a bug.
  • **Coverage gap:** point it at a coverage report — "here's the uncovered lines, write tests that exercise them" — to close specific holes rather than re-testing what's already green.

watch out for

  • Don't let it make a failing test pass by softening the assertion. Ask explicitly: is the test wrong, or the code? A green suite that asserts nothing is worse than no suite.
  • Tests that just mirror the implementation line-for-line break on every refactor and catch nothing. Test *behaviour and contracts*, not internals.
  • Read the generated tests — a wrong test that passes encodes a wrong belief about your code and will mislead the next person.

you'll end up with A scary, untested module becomes a covered one you can change with confidence — and the act of writing the suite flushes out the one or two real bugs that were hiding in the edge cases.