Tech Update / Adventures with Claude Code #18

Tests first – the best prompt is a failing test

"Build me a function that calculates discounts." Claude delivers. The code looks good, compiles, and is still wrong, because I forgot to mention that discounts can't be combined.

The problem isn't Claude. The problem is my description. And the most precise description I know is a test.

🔴 The workflow that works for us

  1. Claude writes only the tests first. Explicitly: "No implementation yet."
  2. I read the tests. This is where I find the gaps in my own requirement.
  3. Claude runs the tests and confirms: they fail.
  4. I commit the tests.
  5. Only now: "Implement until all tests pass. Don't change the tests."

🔁 Why it works so well

Claude gets a clear, verifiable goal. Instead of guessing once, a loop runs: write code, run tests, read errors, fix. Claude can do that without me, and it's pretty persistent about it.

And in the end I don't have to understand every line of the implementation to know whether it does the right thing. The tests tell me.

💡 My tip

"Don't change the tests" isn't just a line in our prompt. During this phase, a PreToolUse hook (part 11) blocks writes to *.spec.ts. Anyone who wants to change a test has to justify it, the AI included.

A word of caution:

Claude gets creative when it comes to making tests pass. A hard-coded return value, a skip, an expect that's a little too loose. So look at the diff carefully. Also: tests written by Claude sometimes test the implementation rather than the requirement. Good test cases are still your job.

My rule of thumb:

  • Requirement clear and testable? Tests first, then code.
  • Requirement still fuzzy? Plan mode first (part 10), then tests.
  • UI, prototype, throwaway code? Trying it and looking at it is enough.

← Back to overview