TDD with AI: writing tests with Claude Code using red-green-refactor (2026)
TDD with AI means you write a failing test first, let Claude Code write the minimum code to turn it green, then refactor while keeping it green - the Red -> Green -> Refactor loop. The test acts as a "definition of done" the AI cannot grant itself. The single most important gotcha: Claude defaults to writing code first, so you have to actively force it to write tests first using phase-separated prompts and a rule in CLAUDE.md.
What is TDD with AI?
TDD (Test-Driven Development) is a way of writing code where you write the test first - let it fail - then write just enough code to make it pass, and finally clean it up (refactor) without turning the test red again. That is "classic" TDD, and it has been around for years. "TDD with AI" simply means you let Claude Code (or a similar AI assistant) do both jobs: write the tests and write the implementation that satisfies them, while you stay in charge of defining the requirements and verifying the result.
The core difference from "ask AI to code and then have it add tests afterward" is order. In TDD, the test you write first is an executable spec: it describes the exact input, output, and edge cases before a single line of real code exists. Claude Code then writes code to make that test go green, instead of writing whatever it wants and grading its own homework.
If you are not yet comfortable working through a process alongside AI, read what vibe coding is and how it differs from a disciplined workflow first to see where TDD fits in the bigger picture. TDD is one of the disciplines that keeps vibe coding from turning into a pile of code nobody can control.
Why does TDD fit Claude Code so well?
Claude Code is at its best when the "definition of done" is something runnable and self-checking - and a test is exactly that. When you say "make this function work correctly," the AI has to guess what you mean. When you say "make these 8 tests pass," it has a clear binary target: red or green, with no gray zone where it can "assume it is done."
Three reasons make this pairing click:
- A test is a spec and a safety net at the same time. It describes the requirement and simultaneously catches breakage the moment the AI changes something else by mistake. In a codebase the AI edits constantly, that safety net is what keeps you from "fix one thing, break three others."
- A tight feedback loop. Write test -> run -> read the error -> fix until green. Claude Code can run tests in the terminal and read the real output, so it iterates across several rounds without you copy-pasting errors by hand.
- A guard against the AI missing the requirement. This is the point few people say out loud: writing the test first forces you (and the AI) to nail down the requirement before coding. A lot of "technically correct but wrong intent" bugs vanish once the requirement is frozen into a test.
Anthropic itself lists TDD as a recommended workflow when working with Claude Code in Claude Code best practices (Anthropic, 2025): write the tests, confirm they fail, then write code until they pass. This is not a trick someone made up - it is how the tool's own maker suggests using it.
The Red-Green-Refactor cycle with Claude Code
The whole of TDD fits in three steps, repeated for each small slice of a feature. With Claude Code, each step maps to one prompt and one clear output expectation.
Step 1 - Red: write a failing test (no code yet)
You ask Claude to write a test for the desired behavior, and only the test. Running it must be red, because the implementation does not exist yet.
Write a unit test for validate_email(email) in src/validators.py using pytest.
Cover these cases: valid email, missing @, missing domain, empty string, None.
The test MUST fail because the function does not exist yet. Do NOT write any code for validate_email.
Expected: a test_validators.py file with a handful of cases, and running pytest reports an ImportError or red tests. Red here is correct - it proves the test actually checks something that does not exist yet.
Step 2 - Green: write the minimum code to pass
Only now do you let the AI write the implementation, and stress "minimum" so it does not tack on extra features.
Write the MINIMAL implementation of validate_email so every test in
test_validators.py passes. Run `pytest -q` and paste the real results back to me.
Do not add features beyond what the tests cover.
Expected: just-enough code, and the pytest output flips to green. Make the AI paste the actual run output; do not trust a bare "it passes."
Step 3 - Refactor: clean the code, keep it green
Once it is green, you have a safety net to clean things up freely.
Refactor validate_email for readability (extract the regex into a constant, use clear names).
Do NOT change behavior. Re-run `pytest -q` after editing to prove it is still green.
Expected: cleaner code, tests still fully green. If a test goes red during a refactor, that is a signal you just changed behavior by accident - fix it right away.
A real test-first session with Claude Code (step by step)
That is the theory; here is a real session on a small feature: a function parse_price("1.299.000d") that returns the integer 1299000. This is pure logic with clear input/output - ideal ground for TDD.
Step 1 - ask for a red test. I open Claude Code in the project folder and type:
Write pytest for parse_price(s) in src/pricing.py:
- "1.299.000d" -> 1299000
- "50.000 d" -> 50000
- "0d" -> 0
- a string with no digits -> raise ValueError
Write only the test. The function does not exist yet, so the test must fail.
Step 2 - ask for the minimum code to go green. After confirming the tests are red as expected:
Write the minimal implementation of parse_price so all 4 tests pass.
Run `pytest -q` and paste the output. Do not handle cases outside the tests.
Claude writes a function that strips non-digit characters, casts to int, and raises ValueError when empty. It runs the tests itself and returns a green result.
Step 3 - refactor. I tell Claude to pull the digit-extraction logic into a helper and add a docstring, and to re-run the tests to prove behavior is unchanged. Still 4 green. The whole session takes a few minutes, and the key point is that I never had to take "it is done" on faith - every claim came with real pytest output attached.
How to FORCE Claude Code to write tests FIRST (so it does not code first)
This is the biggest headache, and the reason many teams drop TDD after a few days: Claude Code, like most AI assistants, tends to jump straight into the implementation and only bolt on tests for show. It is trained to "solve the problem," and to it, writing code looks more like solving the problem than writing a test. Three mechanisms force the issue effectively:
1. Phase-separated prompts. Do not fold "write function X and a test for it" into one sentence - that is an invitation for the AI to code first. Split it hard: the Red step says only "write a FAILING test for X, do NOT write code yet," and you move to Green only once the test is red. Putting "do not write code yet" in caps or bold noticeably improves compliance.
2. A test-first rule in CLAUDE.md. This is the most durable approach - write the rule once, apply it to every session. Add this block to your project's CLAUDE.md file:
## TDD rules (mandatory)
- Always write tests BEFORE the implementation for any new logic/function.
- Order: (1) write a failing test, (2) run `pytest -q` to confirm red,
(3) write the minimal code to pass, (4) refactor while staying green.
- Do NOT write any implementation during the Red step.
- Do NOT edit tests just to make existing code pass.
- After every change, run the REAL tests and paste the output; never claim "it passes" on faith.
If you have never configured this file, see the guide to writing a solid CLAUDE.md (enforcing test-first) - it is the on/off switch for discipline across the whole project.
3. A phase gate with a subagent. The advanced move: use a dedicated test-writing subagent and do not show it the implementation plan. When the "test writer" does not know what the code will look like, the tests stick to the desired behavior rather than the code you intend to write - which avoids tests shaped to fit and "make it green." The way to organize multiple agents by phase lives in the brainstorm -> plan -> cook -> ship workflow.
Common mistakes in TDD with AI (anti-patterns)
TDD with AI fails in very predictable ways. Spot them early so you do not fool yourself into thinking you are "doing TDD":
| Anti-pattern | Why it is wrong | How to fix it |
|---|---|---|
| Doing Red + Green in one shot | The AI writes code first and then adds tests that match the code - no longer test-first, and the spec value is gone | Split into two separate prompts; only write code after confirming the test is red |
| Asking the AI to "write tests" for existing code | That is test-after, which only locks in current behavior (bugs included) and does not drive the design | For old code: write tests for the desired correct behavior before changing it |
| Verification gap: the AI reports "done" without running the tests | The AI can imagine a passing result without actually executing it | Always require real test runs plus pasted output; build layers: lint -> unit -> e2e |
| Over-mocking | Mocking too much makes the test check the mock, not the real logic | Only mock I/O boundaries (network, DB); test pure logic for real |
| Trivial tests just "for green" | assert True or a test that restates the code - meaningless | Every test must assert one specific behavior, with edge and error cases |
Of these, the verification gap is the most dangerous because it is silent. When you are stuck on a test that stays red or the AI is going in circles, do not let it "make it green" by loosening the test - switch to methodical debugging (see debugging with AI) and check the quality of the change with a round of AI code review before you commit.
Automating TDD: hooks and skills that enforce the phase gate
Manual discipline drifts easily. Two ways to automate so the phase gate does not depend on your memory:
Hooks that run tests automatically. Claude Code supports hooks that run after each file edit. You configure a hook to run pytest -q (or npm test, vitest run) after every edit; if a test is red, the hook flags it immediately so the AI has to fix it before moving on. This turns "remember to run the tests" into "cannot forget to run the tests."
Skills/subagents with the process built in. Instead of rewriting the test-first convention for every project, you can use a prebuilt kit.
Speed it up with a prebuilt kit: If you would rather not build the hooks and conventions from scratch, the AgentKit kit for Claude Code (20% off via link) (agentkit.best, the
akCLI - not to be confused with OpenAI's AgentKit) ships with 60+ skills and 30+ workflows for engineers, including a code-review workflow. You can pair these with your red-green-refactor loop to get an automatic phase gate and review without the manual setup. Details in the Engineer Kit review. The Engineer Kit currently costs $99 (the site does not mention a recurring fee).
Whether you build it yourself or use a kit, the principle does not change: the machine has to be the one that runs the tests and reports the result - not the AI self-declaring it.
When you should and should NOT use TDD with AI
TDD with AI is not a silver bullet. Be honest about where it shines and where it gets in the way:
Use it when: business logic, pure functions (clear input -> output), data processing, backend APIs, and especially bug fixing - writing a test that reproduces the bug (red) and then fixing it green is the tidiest bug-fix workflow there is. This is also where TDD pays off most when you use Claude Code to build a backend API, because an endpoint contract is easy to freeze into a test.
Less of a fit when: the exploration/prototype phase where the requirements are still fuzzy (tests you write will get deleted constantly), UI styling and visual feel (tests are expensive and cannot catch "looks good/bad"), or a one-off script. When the requirement is still vague, forcing test-first only slows you down - prototype freely, and once you have locked in the behavior, come back and wrap tests around the parts worth keeping.
Frequently asked questions (FAQ)
Does TDD with AI replace manual TDD?
It does not replace the principle, only who types. You still have to decide what the test checks and judge whether the test is meaningful; the AI handles the writing and running. The red-green-refactor discipline is still yours.
Are the tests Claude writes correct and complete?
Usually correct for the basic cases, but it often misses edge cases (empty, null, negatives, unicode, network errors). Read the tests the AI wrote and ask it to add edge cases before trusting them. The test is the spec, so you have to approve the spec.
Which framework - pytest, Jest, or Vitest?
Use whatever your project already uses; Claude Code is fluent in pytest (Python), Jest, and Vitest (JS/TS). What matters is naming the framework explicitly in your prompt or CLAUDE.md so the AI does not pick one at random.
Do I need to know how to write tests before doing TDD with AI?
You should know the basics. You do not need to be great at writing tests, but you need enough to read and judge the tests the AI writes - otherwise you will sign off on meaningless ones. Treat TDD as a way to level up your own testing skills while you work.
Are AI-written tests trustworthy enough to block regressions?
They are trustworthy under two conditions: you reviewed the tests, and the tests were actually run (not the AI self-declaring a pass). Add a lint -> unit -> e2e layer to cover the AI's tendency to report "done" too early.
Can I apply TDD with AI to a legacy project?
Yes, but in a different order: for legacy code, you first write "characterization tests" that lock in the current behavior, then refactor safely. For brand-new features added to an old project, it is still test-first as usual.
Conclusion and next steps
TDD with AI boils down to one loop: write a red test -> let Claude Code make it green -> refactor while keeping it green, and always make the machine run the real tests instead of trusting the AI's word. The key is not a more powerful tool, it is being able to force the AI to write tests first with phase-separated prompts and a CLAUDE.md rule. Next step: wire TDD into a complete process with the brainstorm -> plan -> cook -> ship workflow, and shore up your process foundation through vibe coding done the right way.
Want a stronger Claude Code right now? If you would rather skip building the hooks, test-first conventions, and code-review workflow yourself, the engineer kit packages those pieces to drop straight into your red-green-refactor loop.