Dashboard

How to Get an AI Coding Agent to Write Tests First

Most agents write a test and its implementation in the same breath, so the test never fails for real. Here is the exact instruction that forces a genuine red-green-refactor cycle.

Steve Jefferson
Steve Jefferson
Developer Advocate
8 September 20261 min read

How to Get an AI Coding Agent to Write Tests First

Telling a coding agent to “do TDD” rarely works. Ask most agents for test-driven development and they write a test, then the matching implementation, in the same response, without ever running the test in a genuinely failing state. That satisfies the words “tests first” without doing what TDD is for. The fix is procedural: require the agent to produce a failing test and paste real failure output before it writes any implementation. That one checkpoint, enforced turn by turn, is what separates actual red-green-refactor from an agent writing tests to match whatever code it already decided to produce.

Why agents default-cheat test-first workflows

Coding agents are trained mostly on codebases where implementation and tests ship together, so their default completion pattern is implementation first, tests after, if at all. Ask directly for test-driven development and most agents technically comply, generating a test file and an implementation file in the same turn. Functionally that is not TDD, the test never exists in a failing state against real code, so it never actually specifies anything, it just documents what the implementation happened to do.

The more subtle version of the same cheat is writing a test that describes the implementation instead of the requirement. Writing code and its tests in one uninterrupted pass answers “what does this function do” and encodes that as the test, instead of answering “what should this function do” and holding the implementation to it. Researchers tracking agent-generated pull requests have documented this directly: relaxed assertions, swallowed exceptions, and checks that only verify a function exists rather than that it behaves correctly.

It's a close cousin of a failure mode that shows up once tests already exist: an agent under pressure to pass a suite loosening or rewriting the tests themselves instead of fixing the code. Same root cause, letting one pass of work define both the check and the thing being checked.

The instruction that actually stops it

The single most effective line to add to a test-first prompt is a hard stop on implementation until failure is demonstrated:

text
Write one failing test for [behavior]. Do not write or modify any implementation code yet. Run the test and paste the actual failure output. I will confirm the test fails for the right reason before you write any implementation.

This works because it creates an observable, hard-to-fake checkpoint. An agent can claim a test passed, but a real failure trace carries specific detail, an import error, an assertion mismatch, a stack trace, that only appears when the test actually ran against missing or wrong behavior. If the agent reports a pass on the first run of a test for code that doesn't exist yet, something is wrong: either it wrote the implementation first, or the test has no real assertion in it.

Two more clauses close the common workarounds agents use to get around this instruction:

  • “Do not write the test and the implementation in the same response” stops agents from batching both together to save a turn.

  • “The test must exercise real behavior, call the function and check its output, not just that a class or method exists” stops the shallow-assertion version of the cheat.

A prompt sequence that reliably produces test-first code

Individual instructions help, but the workflow that actually holds up across a session is a fixed sequence you repeat for every new piece of behavior:

  1. State the behavior spec precisely, concrete inputs and expected outputs. “Write tests for the discount function” lets the agent invent both the spec and the test.

  2. Ask for exactly one failing test at a time. Multiple tests in one turn make it easy to slip an implementation in alongside them.

  3. Require the agent to run the test and paste the failure output before doing anything else.

  4. Only after confirming a real failure, ask for the minimal implementation needed to pass that one test, nothing more.

  5. Run the tests again and confirm the suite is green before moving to the next behavior.

  6. On a refactor pass, require tests to stay green after every individual change, not just at the end.

A worked example

The sequence applied to a small pricing function, actual prompts and the agent's real output at each step:

text
You: Write one failing pytest test for calculate_discount(price,
quantity): quantity >= 5 applies a 10% discount, otherwise price is
unchanged. Don't write calculate_discount yet. Run the test and show
me the failure.

Agent writes:
def test_bulk_discount_applies_at_five_units():
    assert calculate_discount(100, 5) == 90.0

Agent runs pytest, pastes:
ImportError: cannot import name 'calculate_discount' from 'pricing'

You: Good, that's a real failure. Now write the minimal
calculate_discount to make this pass. Nothing else.

Agent writes:
def calculate_discount(price, quantity):
    if quantity >= 5:
        return price * 0.9
    return price

Agent runs pytest again:
1 passed in 0.02s

You: Now add a failing test for quantity == 4 (no discount), same
rules as before.

The implementation is trivial precisely because the test forced it to be. Nothing was written that the failing test didn't demand, which is the actual point of red-green-refactor, not coverage for its own sake.

Where the discipline breaks down in longer sessions

The checkpoint holds for one function in one turn. Over a longer session building several features, agents drift back toward batching: writing three functions and their tests together to save time, or skipping the “show me the failure” step because the last ten tests all failed correctly and it assumes this one will too. Restate the rule at the start of each new behavior rather than assuming it carries forward from earlier in the conversation.

The same discipline matters later, too. A suite written correctly today can start failing intermittently as the codebase changes around it. The fix is not to weaken the assertion, it's working out whether the test or the code is wrong, a narrower version of the same problem covered in how to prompt an AI agent to fix a flaky test.

When strict test-first isn't worth enforcing

This workflow has a real cost in turns and tokens, and it isn't the right default for everything. Early prototyping, exploratory scripts, or throwaway glue code where requirements aren't settled yet are cases where writing tests up front just encodes guesses. It's reasonable to let an agent prototype first and backfill tests once behavior stabilizes. If you're scaffolding an entire application rather than one function, the same tradeoff shows up at a larger scale, worth weighing against how the sequencing works when building an app with AI end to end.

For anything with real edge cases, billing logic, auth, parsing untrusted input, the failing-test checkpoint pays for itself. It's cheaper to spend a few extra turns forcing a real red test than to debug a plausible-looking implementation that was never actually specified. This applies across most AI coding tools, not one product, since the underlying cause, implementation-first training data, is common to the category.

Frequently asked questions

Why does my AI coding agent write the test after the code instead of before?

Its default completion pattern comes from training data where implementation and tests are written together or implementation first. Asking generally for “test-driven development” usually isn't specific enough to override that; you need to explicitly forbid implementation before a failure is shown.

How do I know if an agent's failing test is real and not staged?

Ask for the actual terminal output, not a summary. A genuine failure carries specific detail, an import error, an assertion diff, a line number, that's easy to spot as missing or generic if the agent skipped actually running it.

Can I make an AI coding agent follow strict TDD without retyping instructions every time?

Yes. Most agent tools support saved system prompts or project rules files that persist across a session. Put the failing-test-first rule and the one-behavior-at-a-time constraint there, though it's still worth restating for a new feature area.

Does this approach work with any AI coding agent, or only Claude Code?

The underlying cause, agents defaulting to implementation-first output, shows up across coding agents generally, not one product. The explicit failing-test checkpoint works regardless of which agent you're prompting, since it's a constraint on process rather than a feature of any one tool.

What's the difference between this and just asking an agent to add more test coverage later?

Coverage added after the fact tests what the code already does, bugs included. A test confirmed failing before the implementation exists tests what the code is supposed to do, and the two catch very different numbers of defects even when the resulting files look similar.

How did this land?

About the author

Steve Jefferson
Steve Jefferson

Developer Advocate

Steve builds something with Swarmz every week and writes up what worked, what broke, and what he'd do differently. Tutorials and hands-on guides are his lane.

Share

Get the next post in your inbox

One email a month. Product updates, engineering posts, and the best of Built with Swarmz.

I agree to receive emails about AI building tips and Swarmz product news. Unsubscribe any time.