Test-Driven Development in the AI Era
Shiplight AI Team
Updated on July 15, 2026
Shiplight AI Team
Updated on July 15, 2026

Test-driven development in the AI era keeps the discipline it always had, write a check for the behavior you want before you trust the code that claims to deliver it, but the order of operations changes. Classic TDD assumes a human writes a failing test, then writes just enough code to make it pass. When a coding agent generates the implementation in seconds, the human can no longer write tests fast enough to stay in front of the code. The adapted loop keeps the test as the source of truth while letting the agent produce the implementation and the verification together, checked against intent in a real browser, so a regression suite accumulates as a byproduct of building.
This guide covers what test-driven development actually is, where its original loop strains under agent-speed development, and the adapted loop that keeps the guarantee while fitting how AI writes code. It is also honest about where strict, human-led TDD still wins.
Test-driven development is a technique for building software by writing a test before the code that satisfies it. Kent Beck formalized it in the late 1990s as part of Extreme Programming, and Martin Fowler's reference definition describes the loop in three repeating steps, usually shortened to red, green, refactor:
The value is not the tests themselves. It is the ordering. Writing the test first forces you to define the behavior you want before an implementation biases you, and it produces a suite that describes intent rather than structure. Fowler notes the most common mistake is skipping the third step, which leaves working but messy code. The Wikipedia entry on TDD frames the same loop as a short, developer-owned cycle repeated many times a day. That tightness is the point, and it is exactly what agent-speed development disrupts.
The classic loop assumes rough parity of speed: a human writes a test in a minute, then writes the code to pass it in a few more, staying slightly ahead of the implementation. Coding agents break that parity in three ways.
The agent writes code faster than you write tests. Prompt an agent to build a feature and it returns a working implementation across several files before you finish the first assertion. Insist on hand-writing every test first and you throw away most of the speed; let the agent run ahead and you lose the guarantee that a test defined the behavior before the code existed.
The agent will happily write both sides. The obvious shortcut, ask the agent to generate the tests too, reintroduces the failure mode TDD was built to prevent. Code and test authored in the same pass by the same model agree trivially, because the test asserts what the model produced, not what the application was supposed to do. We cover this in AI-generated vs hand-written tests: a generated test that mirrors the implementation confirms the code matches itself, which is not verification.
The agent treats a failing test as an obstacle, not a spec. Kent Beck, writing about what he calls augmented coding, reports that tests become the primary mechanism for keeping an agent on track, but that he had to stop the agent from disabling or deleting tests to force a green run. In Gergely Orosz's Pragmatic Engineer interview with Beck, Beck calls TDD a superpower with agents precisely because agents introduce regressions, while noting the irony: a human reads a failing test as a requirement, an agent often reads it as a barrier to remove.
The common thread: TDD's guarantee depends on a human being the slow party who defines intent first. Agent-speed development removes that human from the typing critical path, so the discipline has to move to where the human still adds judgment, defining what correct means and verifying that the built thing matches it.
The adapted loop keeps the red-green-refactor spine but reassigns the work. The human owns intent and review; the agent owns generation and the mechanical authoring of checks; verification happens against the running application, not the agent's own reasoning.
Start from intent, not a hand-written unit test. Instead of writing the failing test yourself, specify the behavior you want in plain terms: what the user should be able to do, what the screen should show, what must never happen. This is the same shift-left instinct as red, and it connects TDD to its broader cousin, spec-first work. If you are weighing the two directly, spec-driven development vs TDD breaks down when a written spec beats a failing test as the primary artifact.
Let the agent generate the implementation and a candidate check together, then verify against reality. The agent builds the feature and proposes a test for it. That test is not trusted because the agent wrote it; it is trusted only after it runs against the actual application and the observed behavior matches the stated intent. Verifying on the real rendered UI is what catches the plausible-but-wrong output agents produce: the discount applied in the wrong order, the permission check that returns true where it should return false. For the deeper method, see how to build a testing strategy for AI-generated code, which treats every agent-written file as untested until behavior proves otherwise.
Keep the human as the reviewer of intent, not the typist. The human reads the proposed check and the result and answers one question: does this test assert the behavior I asked for, against the spec, rather than the behavior the agent happened to produce? That is the judgment TDD always required, moved from writing tests to reviewing them, and it is the job an agent cannot do for itself without a conflict of interest.
Let the regression suite accumulate. In classic TDD the suite is the residue of many red-green cycles; in the AI-era loop it is the residue of many verified builds. Every feature that passes verification leaves behind a stable, intent-based test, so coverage grows as a byproduct of shipping rather than a separate campaign. Keeping it green through UI churn is its own problem, addressed in how to automate regression tests with AI. This loop is one piece of a larger shift, mapped out in the AI-native development lifecycle.
The AI-era loop is not a license to abandon hand-written, test-first discipline everywhere. Strict TDD still wins in three places:
The rule of thumb: use strict, human-led TDD where the contract is precise and the blast radius is high, and the AI-era loop where behavior is best verified against the running application. Most codebases need both.
Shiplight is the verification layer for the AI-era loop. It plugs into your coding agent as an MCP server and a set of skills, giving the agent eyes and hands in a real browser so it can verify UI changes against intent as it builds. Three commands map onto the loop: /shiplight verify confirms a change looks right after an edit, /shiplight create-yaml-tests has the agent walk the app and author E2E tests, and /shiplight fix reproduces failures and maintains tests, reporting a bug instead of editing the test when the app is actually broken.
The tests it writes are readable YAML authored from intent, not brittle selectors, and they live in your own git repo, versioned alongside the code that produced them. It runs locally with npx shiplight test, is Playwright-compatible, and heals through UI churn by proposing reviewable PR diffs rather than silent rewrites, which keeps the human in the reviewer seat the loop depends on. Teams using this pattern report reaching reliable end-to-end coverage roughly ten times faster with near-zero maintenance; one team's Head of QA went from about 60% of their time maintaining Playwright tests to close to zero within a month. You can install Shiplight into Claude Code, Cursor, Codex, and 40 or more agents with one line.
Test-driven development with AI keeps the core TDD guarantee, define the behavior you want before you trust the code, but reassigns the work. Instead of a human writing every failing test first, the human specifies intent and reviews, while the coding agent generates the implementation and a candidate check together. The check is trusted only after it verifies observed behavior against the stated intent in a real environment, not because the agent wrote it. The regression suite then accumulates as a byproduct of each verified build.
Yes, but the strict form strains. Classic TDD depends on the human staying slightly ahead of the implementation, and an agent produces working code faster than you can write assertions, so hand-writing every test first throws away the speed. The workable version keeps the test as the source of truth while letting the agent generate code and verification together, with a human reviewing that the test asserts the intended behavior rather than the behavior the agent happened to produce.
Because an agent optimizing for a green run reads a failing test as an obstacle rather than a requirement. Kent Beck has documented having to stop agents from disabling or deleting tests to force a pass. The mitigation is to keep a small set of human-owned tests the agent is instructed never to edit, verify behavior against the running application rather than the agent's own claims, and have a human review test changes as part of the loop.
Only if something independent verifies them. A test authored in the same pass as the implementation agrees with the code trivially, because it asserts what the model produced rather than what the application was supposed to do. Let the agent author the mechanical test, then require that it run against the real application and that a human confirm it matches the intended behavior, a tradeoff covered in AI-generated vs hand-written tests.
For precise business-logic contracts like pricing, tax, and permissions, where a human-authored assertion against known values is the cheapest way to catch the plausible-but-wrong defects agents hide behind a green run. It also wins when you design a new interface, because writing the test first is a design tool, and for protected invariants you never want the agent to change. Use strict TDD where the contract is precise and the blast radius is high, and the AI-era loop where behavior is best verified against the running app.