
Write Tests With Claude Code: A TDD Workflow That Holds Up
Write tests with Claude Code using TDD: the agent writes tests first, runs the suite and iterates, with rules that stop it weakening or deleting tests.
Want to apply this in your company?
Book a call with Juan →Write Tests With Claude Code: A TDD Workflow That Holds Up
To write tests with Claude Code using a TDD approach, ask the agent to write the tests first from a clear requirement. Confirm they fail for the right reason, freeze them, and only then let the agent implement the code, running the suite on every cycle. One rule holds the whole workflow together: the agent may change the code to pass the tests, but it may not change the tests to pass. Without that rule, a green suite stops proving anything.
Key takeaways
- A test written first works as a specification: it states what the code must do before the agent decides how to do it.
- The useful cycle is short: failing test, minimal implementation, run the suite, adjust, repeat.
- Weakening, skipping or deleting tests is the most common shortcut for an agent that wants a green suite. It must be forbidden by a written rule and by a technical mechanism.
- A person reviews and approves the tests before implementation, then reviews the diff afterward, looking also at what should not have changed.
- When a test seems wrong, the path is to stop and propose the fix separately, never to adjust it in the middle of the implementation.
Why start with the test when the agent writes the code?
A coding agent works well when it gets an objective signal of success or failure. Anthropic's article Building effective agents describes how coding agents benefit from verifiable results, such as automated tests, so they can iterate on real feedback instead of guesses. The test is that signal.
If the agent writes code first and tests afterward, the tests tend to describe what the code already does, mistakes included. You end up with a suite that confirms current behavior, not desired behavior. Reverse the order and the test is born from the business requirement, and the code is judged by it.
There is a second benefit, more practical for the person making decisions: a test is readable by someone who understands the business. An operations owner does not read the code, but can check whether the list of cases covers the situations that matter, such as a customer with no account, a cancelled order or a value outside the allowed range.
What does the workflow look like, step by step?
This is the routine we recommend for a small to medium feature or fix. Each step has a clear owner.
- Describe the requirement in business language, with examples of input and expected output. Whoever knows the rule writes or validates those examples.
- Ask Claude Code to propose the test cases before writing any production code. If you like, use plan mode so it does not edit files at this stage.
- Ask for the tests to be written without any implementation, then run the suite. Confirm the tests fail and fail for the expected reason (a missing function is different from a rule not being met).
- A person reviews the tests: do they cover the requirement? Are there edge cases? Do the assertions check concrete values? After that, make a commit containing only the tests.
- Authorize the implementation with an explicit instruction not to change test files. The agent writes the minimum code, runs the suite, reads the failures and adjusts.
- If the agent concludes that a test is incorrect, it stops and describes the problem. Fixing the test becomes a human decision, in a separate commit.
- At the end, run the full suite, not just the new tests, and review the diff with special attention to any change in tests, test configuration and the pipeline.
- Let continuous integration run the same suite in a clean environment, as a check that is independent of what the agent reported.
The central point is separation: whoever defines the acceptance criteria is not the one trying to satisfy them during implementation.
How do you write tests that serve as a specification?
A vague test leaves room for the agent to pass without being right. A few habits shrink that room.
- One behavior per test, with a name that describes the business rule, for example that a cancelled order does not generate a charge.
- Concrete expected values, written by hand from the requirement, not computed by the same logic that is being tested.
- Explicit edge cases: empty, null, exact limit, duplicates, data in an unexpected format.
- Negative cases: what the system must refuse or ignore.
- External dependencies isolated with test doubles, so the suite is fast and deterministic. For systems that have AI agents in the loop, read how to test an AI agent with mocks and a sandbox.
Tests written by AI deserve the same skepticism as any code written by AI. A test that always passes protects nothing. To go deeper on validation, see AI-generated tests: can you trust them and how to validate. A simple check is to break the code on purpose by changing a condition, then see whether any test fails. If none does, the test is decorative.
How do you stop the agent from weakening or deleting tests?
The risk is real and predictable. When the goal is a green suite and the honest path is hard, the cheapest shortcut is to move the goalposts. This can show up in subtle ways, so the rule needs to name each one.
Start with a block of instructions in the project's CLAUDE.md file, which Claude Code reads as context. Use a short, unambiguous set of prohibitions:
- Do not delete, rename or move test files.
- Do not mark tests as ignored, skipped or expected to fail.
- Do not loosen assertions, swap expected values or replace exact comparisons with generic ones.
- Do not wrap code in error handling that swallows exceptions just to make a test pass.
- Do not hardcode the test's expected value in production code (a fixed result for a known input).
- Do not mock the very unit that is being tested.
- Do not update reference files (snapshots) without approval.
- Do not touch test configuration, coverage thresholds or pipeline files.
- If you think a test is wrong, stop and explain, with evidence.
Written instructions help, but they are not enough, because an agent can fail to follow them in long tasks. So add mechanisms that do not depend on obedience:
- Permission rules in the project settings that deny edits to the test folder during the implementation phase.
- Claude Code hooks that run the suite after edits and block completion if anything fails.
- Mandatory code review for any change to test files, with owners defined in the repository.
- Continuous integration running the full suite in a clean environment that the agent does not control.
- Diff comparison by folder, so changes to tests show up separately from changes to code.
If your team repeats these rules across several projects, package them. See Claude Code skills to turn the workflow into a reusable procedure.
What does it look like in practice? An illustrative scenario
Imagine a custom furniture shop that calculates quotes and needs a function that applies a volume discount, with one exception: customers with a resale contract follow a different table. This is an illustrative scenario, not a real customer.
The person responsible for operations writes four examples in plain language: a small order with no discount, a large order with a discount, a reseller with their own table, and an order with a made-to-measure item, which never gets a discount. Claude Code turns these into tests, and the person reviews them. They notice that the case of an order exactly at the tier limit is missing and ask for it to be added. The suite runs and fails because the function does not exist yet. The tests are committed.
During implementation, the agent creates the function and the suite almost passes. One test, the made-to-measure item, keeps failing. The agent's first idea is to relax the assertion to accept any value less than or equal to the total. The project rule forbids that, so it stops and reports: the function is applying the discount to the made-to-measure item because the exception list is never consulted. It fixes the code, the suite goes green, and the final diff shows changes only in the code folder. Review takes a few minutes because nothing touches the tests.
Without the rule, the visible result would be the same, a green suite, and the business error would reach real quotes.
What if the test really is wrong?
Tests have defects too. A requirement may have been misunderstood, or an expected value may have been copied incorrectly. Forbidding any change with no exception would push the agent to distort the code to satisfy an incorrect test. Use this decision guide:
- If the failure comes from code behavior that contradicts the requirement, fix the code.
- If the requirement and the test disagree, the person who owns the rule decides which one is right, before any edit.
- If the test depends on something unstable, such as time, ordering or an external service, fix the test isolation in a separate, reviewed commit.
- If the test validates a behavior that no longer exists because of a business decision, remove it with the justification recorded in the commit, never as part of the implementation.
- If it is unclear, treat it as wrong code until there is evidence to the contrary.
The agent can help with the investigation by gathering evidence and hypotheses, as described in how to debug production bugs with AI. The decision to move the goalposts stays human.
How does this workflow fit our method?
The method we use with companies (see how Juan Carlo works with companies) follows four moves: map, limit, pilot and hand over. Applied to testing with Claude Code, mapping means understanding how the team validates changes today and where the business rules that matter most live. Limiting means defining what the agent may edit, which commands it may run and which folders are protected. Piloting means choosing one small, real feature, running the workflow with the executions recorded, and agreeing in advance on the success criterion, for example that no test was changed without approval. Handing over means giving the team the documented procedure and deciding, based on the pilot, whether to expand, adjust or stop.
To evaluate the agent more broadly, Anthropic also publishes material on how to think about evaluations (Demystifying evals for AI agents) and on support structures for long tasks (Effective harnesses for long-running agents). They are useful reading for anyone who wants to go beyond the basic cycle described here.
Frequently asked questions
Can Claude Code write good tests on its own? It can write useful tests when it gets a clear requirement and concrete examples, but it should not be their only reviewer. A person needs to check coverage, edge cases and expected values before implementation.
Do I need to block test editing completely? During the implementation phase, yes, it is the safest approach. Outside that phase, editing tests is normal and necessary, as long as it goes through review and lands in a commit separate from the production code.
Does a green suite mean the feature is correct? Not necessarily. It means the code satisfies the existing tests, and that is only worth as much as the quality of those tests. That is why we combine test review, a careful diff and independent execution in continuous integration.
Does this workflow work for teams that do not code every day? It works even better when someone from the business validates the examples, because the test becomes a readable record of the rule. The technical part, such as configuring permissions and hooks, should stay with whoever maintains the repository, and the pilot should start with a small, low-risk change.