“Make the agent do TDD” has become one of those pieces of folk wisdom that spreads through engineering Slack channels without anyone actually measuring it. The reasoning sounds solid on the surface: TDD makes human developers write better code, so telling an AI agent to write a failing test first, then implement, then refactor, should produce the same benefit. I’ve told agents to do exactly this on more than one project.
A controlled experiment out of Thoughtworks just tested that assumption directly, with real token counts and blind quality judging instead of vibes. The result should change how you prompt coding agents, and it’s not what the folk wisdom predicted.
The Experiment Setup
The design was deliberately simple and adversarial to bias: Claude Sonnet 4.6 generated code under two different prompting strategies — one instructing strict red-green-refactor TDD (write a failing test, run it, confirm failure, implement, run again, refactor), the other a straightforward “implement this, then write tests” spec-first approach. A separate model, Claude Opus 4.8, blind-judged the resulting code quality without knowing which method produced which output. Five batches of tasks ran through both conditions.
This blind-judging step matters more than it sounds like. Self-reported “the TDD version felt more thorough” is exactly the kind of bias a controlled experiment exists to remove.
The Token Cost Numbers
This is where the folk wisdom collides with reality:
| Task size | TDD tokens | Non-TDD tokens | Multiplier |
|---|---|---|---|
| Small tasks | 1,018,245 | 119,815 | 8.5x |
| Larger tasks | ~2.96x higher | baseline | 2.96x |
For small, well-scoped tasks, the TDD loop cost 8.5 times more tokens than spec-first prompting. On larger tasks the multiplier dropped to roughly 3x — still a significant cost, just less extreme because larger tasks amortize the red-green cycling overhead across more actual implementation work.
Where does that cost actually go? Every red-green cycle round-trips through the model multiple times per unit of functionality: write test, run test (confirm red), write implementation, run test again (confirm green), then a refactor pass. Each of those steps re-reads context, re-reasons about the current state, and re-generates output. A human doing TDD keeps all of that state in their head for free; an agent re-derives a meaningful chunk of it from scratch on every loop iteration, because “state” for a model is whatever’s in the context window, not a persistent mental model.
The Quality Result Nobody Expected
Here’s the part that actually surprised me: blind judging by Opus 4.8 preferred the non-TDD output. Not tied — preferred.
Mutation testing scores, a reasonable proxy for how well tests actually catch bugs, came back statistically indistinguishable between the two approaches. The TDD loop’s incremental, test-first structure — write one test, make it pass, write the next test, make it pass — nudged the agent toward locally-correct, narrowly-scoped implementations that satisfied each test as it arrived, without stepping back to consider the full problem space. That narrowed edge-case coverage rather than expanding it, which is the opposite of the argument for why TDD should help.
For a human, red-green-refactor forces you to think about interface design and edge cases before you commit to an implementation, because writing the test first requires imagining how the code will be called. An agent doesn’t have that same cognitive constraint — it can hold the full problem in context regardless of whether you make it write a test first, and forcing the sequential loop doesn’t add discipline it was actually missing. It just adds process overhead without the underlying cognitive mechanism that made the process valuable for humans in the first place.
Why This Matters: Folk Wisdom Doesn’t Transfer
This is a pattern I keep running into with agentic coding: practices that work for human developers get transplanted onto agent workflows on the assumption that “good practice is good practice,” without checking whether the mechanism that made the practice work actually applies to how a model operates. TDD’s value for humans comes substantially from forcing a specific cognitive sequence — think about the interface, then think about the implementation. An LLM doesn’t sequence its reasoning the way a human does; it can (and does) consider interface and implementation simultaneously within a single generation. Forcing the human sequence onto it doesn’t recreate the benefit — it just adds the process cost without the cognitive benefit that justified the cost for humans.
What I’d Actually Do Instead
Based on this data, here’s the prompting pattern I’m switching to for agent-driven implementation work:
# Old pattern: iterative TDD loop
"Write a failing test for X. Run it and confirm it fails.
Implement the minimal code to pass. Run the test again.
Refactor. Repeat for the next requirement."
# New pattern: spec-first, verify-after
"Here is the full spec for X, including edge cases: <spec>.
Implement X completely. Then write a comprehensive test suite
covering the happy path, documented edge cases, and error
conditions. Run the full suite and fix any failures."
The difference isn’t “skip tests” — it’s “stop forcing sequential red-green cycling when the model doesn’t need the sequencing to think clearly.” Write the full spec up front (the part of TDD that’s actually valuable — clarifying requirements before implementation exists), have the agent implement against it directly, then generate a comprehensive test suite in one pass instead of one test at a time.
Where I’d still consider an iterative loop: long-running autonomous agents operating without a human in the loop for extended periods, where an incremental test suite functions as a regression safety net across many sequential changes rather than a design-forcing function for a single implementation. That’s a different problem — regression protection over time — from the one TDD is usually invoked to solve in a single coding session.
The Actual Lesson
Before adopting a human engineering practice as an agent-prompting pattern, ask what mechanism makes the practice valuable, and check whether that mechanism survives the transfer. TDD’s mechanism — sequential cognitive forcing — doesn’t survive contact with a model that doesn’t reason sequentially the way people do. The token cost data here is the concrete proof, but the more useful takeaway is the check itself: measure before you copy a human practice onto an agent, because “worked for developers” and “works for models” are not the same claim.
Thuận Lương is a Technical Lead with 15+ years in .NET, cloud architecture, and AI systems. He writes about real-world lessons from building production systems.