Test-Driven Agent Development
Using TDD workflows to guide agents toward correct implementations
Overview
Every technique we have covered so far -- CLAUDE.md, structured prompts, review workflows -- gives the agent guidance. But guidance is inherently ambiguous. The agent might interpret "handle errors properly" differently than you do. Test-driven development solves this by giving the agent something better than guidance: a machine-verifiable definition of done. When you write tests first and then tell the agent to make them pass, there is no ambiguity about whether the implementation is correct. The tests say yes or no. This lesson covers why TDD and agents are a natural pairing, how to structure the workflow, and what makes tests effective as agent specifications.
Why TDD and Agents Are a Natural Fit
In traditional TDD, the developer writes a test, then writes the implementation, then refactors. The cycle is fast but manual. With agents, the cycle changes in a powerful way:
- Human writes the test (defines what "correct" means)
- Agent writes the implementation (does the mechanical work)
- Test runner validates the result (provides objective feedback)
- Agent fixes failures if needed (iterates without human intervention)
This division of labor plays to each party's strengths. Humans are good at defining requirements and judging correctness criteria. Agents are good at generating code that satisfies constraints. Test runners are good at providing fast, unambiguous feedback.
TDD-with-agents flowchart: the human writes a test, tests run and show RED (failing). The agent implements code, then tests are checked — if they fail, the agent reads failures and tries again. If they pass, the human reviews the implementation. If refinement is needed, the human adds more tests and the cycle restarts. If accepted, the code is committed.
Tests are the best specification language for agents. Unlike natural language, tests are precise, executable, and binary -- they pass or they fail.
The TDD-with-Agents Workflow
Here is the workflow step by step:
Step 1: Write the test. Define the behavior you want. Be specific about inputs, outputs, and edge cases. Do not worry about how the implementation will work -- focus on what it should do.
Step 2: Run the test and confirm it fails. This is the "red" phase. The test should fail because the implementation does not exist yet. If it passes, your test is not testing anything new.
Step 3: Hand off to the agent. Tell the agent which test file to make pass and any relevant constraints.
Step 4: Agent implements and iterates. The agent writes code, runs the tests, reads failures, and fixes issues in a loop until all tests pass.
Step 5: Human reviews. Even though tests pass, review the implementation for approach, readability, and architectural fit. If something is off, add more tests that constrain the approach and repeat from step 3.
Writing Tests the Agent Can Act On
Here is an example. You want a function that calculates shipping cost based on weight and destination zone. You write the test first:
This test suite is effective for agents because:
- It specifies exact inputs and expected outputs
- It covers the happy path, edge cases, and error conditions
- It reveals the business rules implicitly (base rate, per-kg surcharge, zone multiplier)
- It tests boundary conditions (exactly 1kg)
Prompting the Agent for TDD
With the test written, the prompt to the agent is straightforward:
The beauty of this approach: the prompt does not need to explain the business logic. The tests already encode it. The agent reads the tests, reverse-engineers the requirements, and implements accordingly.
The Iteration Loop
Here is what happens under the hood when the agent runs:
Iteration loop sequence: the agent reads the test file, analyzes expectations, writes a first implementation attempt, and runs the tests. The test runner reports 4 passed and 2 failed. The agent reads the failure messages, updates the implementation (attempt 2), and runs tests again. This time all 6 tests pass, and the agent is done.
The agent might not get it right on the first try. That is fine. The iterative loop is the mechanism that makes TDD with agents robust -- the agent keeps adjusting until the tests pass. This is qualitatively different from generating code in a single shot and hoping it works.
Writing Tests That Guide, Not Over-Constrain
There is an art to writing tests for agent consumption. Tests that are too specific about implementation details prevent the agent from finding valid alternative solutions. Tests that are too vague do not provide enough signal.
Good: test behavior
- "Given this input, the output should be X"
- "When this error occurs, the function should throw Y"
- "The result should contain items sorted by date"
Problematic: test implementation
- "The function should use a for loop, not map"
- "The function should call helperFunction exactly 3 times"
- "The internal cache should have 5 entries after this call"
The first set constrains what the code does. The second constrains how it does it. When working with agents, you want to constrain the what and let the agent figure out the how.
Write tests that describe the contract, not the mechanism. The agent needs freedom to choose its approach.
Scaling TDD with Agents
For larger features, break the work into test-driven slices:
Scaling TDD with slices: three sequential slices. Slice 1 (Data Model) — human writes model tests, agent implements. Slice 2 (Business Logic) — human writes logic tests, agent implements. Slice 3 (API Layer) — human writes API tests, agent implements. Each slice builds on the previous one.
Each slice follows the same pattern: human writes tests, agent implements. The slices build on each other -- the data model tests pass before business logic tests are written, and business logic passes before API tests are added. This gives the agent a stable foundation to build on at each step.
Handling Surprising Agent Implementations
Sometimes the agent's implementation passes all tests but takes an approach you did not expect. Perhaps it uses a lookup table where you expected a formula, or it flattens a nested structure you assumed would stay nested.
When this happens, you have three options:
- Accept it -- if the tests pass and the approach is maintainable, the agent may have found a valid alternative you had not considered
- Add constraining tests -- write tests that make the unwanted approach fail. For example, if you need the formula approach for extensibility, add tests with inputs that a hardcoded table cannot cover
- Add prompt constraints -- tell the agent "implement this using a formula-based approach, not a lookup table"
Option 2 is usually the best. It keeps the specification in tests (where it belongs) rather than in natural language (where it is ambiguous).
TDD in CI: The Automated Version
TDD with agents can be fully automated in CI. When a developer pushes test files without implementations, a CI workflow can trigger the agent to fill in the gaps:
This creates a workflow where developers write the specification (tests) and the agent does the implementation work, all within CI.
Summary
Test-driven agent development is the most reliable way to get correct implementations from AI agents. Tests provide what natural language cannot: an unambiguous, machine-verifiable definition of done. The workflow is simple -- human writes tests, agent implements, test runner validates, agent iterates until green. The key to effective TDD with agents is writing tests that constrain behavior (what the code does) rather than implementation (how it does it), giving the agent freedom to find its own approach while ensuring correctness. Break large features into test-driven slices, and the agent can build complex systems one verified piece at a time. In the next lesson, we will close the loop by examining how to continuously improve your agent configuration based on real-world performance.