Apply to my task
arXiv:2610.13065 ★ 95 Oct 9, 2026

TestSuiteBench: green tests from an agent don't prove the code works

Key result

Green tests from an agent prove almost nothing: the best model caught only about 55% of deliberate code breakages, most under 40%. The approach from the paper lets you check the real strength of your tests and make the agent write checks for every requirement, not just the main scenario. Take working code, break exactly one requirement in it, and see whether even one test fails. This is called a mutation. If nothing fails, the tests are hollow, no matter how nice the "all 120 passed" report looks.

01

TL;DR

A coding agent writes lots of valid tests, but weak ones. Almost all of them pass on the reference implementation. But introduce a bug against a specific requirement, and most of the tests won't notice. The researchers measured this with mutations: take a working program, deliberately break one requirement in it, and see whether even one test fails. The best agent caught only about 55% of these breakages; most of the others, under 40%.

The headline finding: the agent understands the specification but is bad at designing checks. It writes a test for the main scenario and skips input combinations and edge cases. For example, it tests a command with one file even though the requirements say "accepts multiple files." It also produces noticeably fewer tests than the human reference: for one of the models, about five times fewer. The problem isn't that the requirements are unclear. When the agent was also given a working program to check against, test strength barely changed.

The practical takeaway: a message saying "all 120 tests passed" tells you nothing about the quality of the checks. Demand tests for every requirement and for combinations of inputs, and check their strength by breaking the code. Two more levers confirmed in the paper: a detailed specification and a higher reasoning level for the model.

Want this for your own case? Apply this study to your task: AI adapts its method to what you are working on and writes the prompt.

02

Method Blueprint

The paper is a benchmark, not a technique. But you can reproduce its way of measuring test strength by hand:

STEP 1: Give the agent a detailed specification (organized by requirement) → a test suite
STEP 2: Run the tests on the working version → share of valid tests (V)
STEP 3: Break the code in exactly one requirement (a mutant) → one mutant per requirement
STEP 4: Run the tests on the mutant → did at least one fail? Yes = mutant killed
STEP 5: Share of killed mutants (M) = the real strength of the tests

Steps 3–4 can be handed to the agent itself as a separate request. Then it becomes a self-check, which nobody in the paper measured (see "Adaptations").

03

Example

Task: You lead a small team building a shipping-cost calculator for an online store. The rate rules: weight, zone, cash on delivery, free shipping on orders of $75+, pickup points and courier. A developer using Claude Code wrote the implementation and the tests, "all green." You want to make sure the tests would catch a bug, for example a forgotten discount on the "cash on delivery + pickup point" combination.

The paper has no ready-made prompt. Below is one assembled from its conclusions: tests per requirement, input combinations, and checking by breakage.

Prompt:

Below is the specification for a shipping calculator. Each requirement is numbered.

[R1] Free shipping on orders of $75 or more — courier only.
[R2] For pickup points, a 10% discount on the rate for orders of $50 or more.
[R3] Cash on delivery adds 3% of the order total, but no less than $2.
[R4] Weight over 40 lb — a surcharge of $0.50 for each additional pound.
[R5] Zone 3 (Alaska and Hawaii) — a 1.8 multiplier on the base rate.
[R6] If the pickup-point discount and cash on delivery combine, apply the discount first, then the fee.

Write the tests in tests/test_delivery.py.

Rules:
1. Separate tests for each requirement. Start each test with a comment giving the requirement number.
2. For each requirement, test the boundaries: exactly at the threshold, $1/1 lb below and above.
3. Separately, write tests for combinations of requirements: every pair from R1–R6 that can overlap, plus the order of application from R6.
4. If a requirement contains a list ("several," "any of"), feed the test at least two or three items, not one.
5. At the end, output a table "requirement → number of tests → which combinations are covered." If a requirement has fewer than three tests, explain why.

Don't tell me the tests are good. Show the coverage in a table.

Result: The agent returns a test file where each test references a requirement. At the end there's a coverage table: for each of R1–R6 you see the number of tests and the combinations. There will be noticeably more tests than with a plain "write tests" request. In a follow-up you can ask the agent to break one requirement at a time and show which tests failed.

04

Why It Works

The LLM's weakness. The agent considers "write tests" done once it has a set of sensible, passing tests. It covers the main scenario and calls it a day. The weak spots sit at the seams: two files instead of one, thresholds, the order in which rules apply. By default it doesn't go looking for them.

The strength. The agent reads specifications well. Implementations built from the same specifications passed up to 93% of the reference tests. If you spell out what to cover and how, it can list it and write it.

How the method uses this. It replaces the question "are there enough tests?" with "what would catch a breakage of this requirement?". That turns a fuzzy goal into a checkable one: every requirement needs tests for boundaries and combinations.

Control levers: - Specification detail. The strongest lever in the paper. With a detailed specification, Sol's test strength was 25.5%; with ordinary repository documentation, 4.0%. The fuzzier the requirements, the weaker the tests. - Specification size. The more requirements, the worse the agent covers them. Cut a large specification into parts and ask for tests section by section. - Reasoning level. For Sol, going from low to xhigh raised test strength from 31.3% to 46.5%, and the cost from $0.45 to $2.4 per task. Diminishing returns, not a miracle. - Number of tests. The models with the weakest results wrote noticeably fewer tests. Requiring "at least N tests per requirement" pushes in the same direction, but the paper didn't test that directly.

05

Prompt Template

Here is the specification. Each requirement is numbered.

{specification_with_numbered_requirements}

Write the tests in {test_file_or_folder}.

Rules:
1. Separate tests for each requirement. Start each one with a comment giving the requirement number.
2. For each requirement, test the boundaries: at the threshold, just below, just above.
3. Separately, write tests for combinations of requirements that can overlap: {list_of_overlaps_or_"find them yourself"}.
4. If a requirement mentions multiple values ({example: "multiple files," "any of the statuses"}), feed the test at least two or three, not one.
5. At the end, output a table "requirement → number of tests → combinations covered".
   If a requirement has fewer than {min_tests} tests, explain why.

Don't assess the quality of the tests in words. Show it in a table.

Put your numbered requirements into {specification_with_numbered_requirements}. If your document doesn't have them, first ask the agent to break the text into numbered requirements.

🚀 Quick start — paste into a chat:

Here's a template for requesting test generation. Adapt it to my task: [your task]. 
Ask me questions to fill in the fields.

[paste the template above]

The LLM will ask where the requirements live, which of them can overlap, and what thresholds and value lists they contain. That's what makes the boundary and combination rules work on your data instead of staying generic.

06

Limitations

⚠️ No tested prompt: The authors did not test whether asking to "cover combinations" improves test strength. They measured the problem and a few factors (specification, reasoning, an executable reference). The template above is our assembly from their conclusions; test it on your own tasks.

⚠️ Narrow project type: 165 command-line utilities in Rust, Go, and C/C++ with "input → output" tests. Web UIs, databases, and integrations with external services weren't tested.

⚠️ Correlation, not causation: The model that created mutants and ran programs on its own wrote the best tests. But Sol beat DeepSeek without doing that. The advice "let the agent break the code itself" is a hypothesis, not a proven technique.

⚠️ Expensive and slow: The best result cost about $10 and 37 minutes per task. Higher spend brings ever smaller gains.

⚠️ The authors' specification isn't yours: Their specifications grew out of reference tests and went through several rounds of refinement. A typical requirements doc is almost always worse, and your result will be closer to 4% than to 25%.

⚠️ Correct specifications don't save you from weak tests: Even with a working program to check against, test strength barely changed. Detailed requirements are necessary but not sufficient.

07

How They Studied It

Researchers from ETH Zurich took 165 open-source programs with reference code and reference tests. From the tests, an agent assembled a detailed specification, about 5,000 words on average. Then they created mutants for each requirement: copies of the program broken in exactly one place. The mutants were refined so that a single test killed them, not half the suite. The share of such mutants rose from 32% to 73%.

The specifications were cleaned up in cycles: agents wrote tests and code from a draft, and the errors were analyzed and classified. If the specification was at fault, it was fixed, until errors caused by inaccuracies fell below 5%. Then six current agents got only the specification, with no internet access, and had to write a full test suite.

The surprise was the gap between the metrics. Tests were 88–96% valid (except for two weak models), implementations from the same specifications passed up to 93% of the reference tests, yet only 38–56% of mutants were caught. So the specification is clear and the agent understands it; what's missing is the skill of designing checks. Two control experiments confirmed this. A working program to check against raised test validity from 94.4% to 98.4% but barely moved strength (37.7% → 38.1%). Replacing the specification with repository documentation crashed test strength from 25.5% to 4.0%: the agent wrote 40% fewer tests, and they were more often wrong. The error analysis showed a typical failure: core functionality is tested, while input combinations and edge cases are skipped.

08

Adaptations and Extrapolations

🔧 Technique: add self-mutation → see the holes in your tests right away

The paper showed that the best models created mutants on their own, but rarely: Opus did it in only 33 of 165 tasks. The idea is to turn that step into an explicit instruction. This is our hypothesis, not a proven technique:

Now take the requirements R1–R6 one at a time. For each one, break the code in exactly one place, 
without touching anything else. Run the tests. Show a table: requirement → what was broken → did a test fail 
(which one). If a mutant survived, write a test that kills it.

🔧 Technique: split the specification into parts → less coverage loss

In the paper, test strength dropped as the number of sections grew. Instead of one request covering 40 requirements, give the agent 8–10 requirements at a time and check the coverage table after each block. This is also our hypothesis, based on their correlation.

09

Resources

  • TestSuiteBench: CodingAgentsStruggle to Generate Strong Test Suites from Specifications (Preprint)
  • Authors: Kazuki Egashira, Niels Mündler-Sasahara, Martin Vechev (ETH Zurich), Mark Niklas Müller (LogicStar.ai)
  • Website: testsuitebench.com
  • Code: github.com/eth-sri/testsuitebench; data: huggingface.co/collections/eth-sri/testsuitebench
  • Related work: ProgramBench (Yang et al., 2026), SWT-Bench (Mündler et al., 2024), SWE-Mutation (Sun et al., 2026), NL2Repo-Bench (Ding et al., 2025)

Research digest

Key result

Green tests from an agent prove almost nothing: the best model caught only about 55% of deliberate code breakages, most under 40%. The approach from the paper lets you check the real strength of your tests and make the agent write checks for every requirement, not just the main scenario. Take working code, break exactly one requirement in it, and see whether even one test fails. This is called a mutation. If nothing fails, the tests are hollow, no matter how nice the "all 120 passed" report looks.

Principle

The agent checks "does the main path work" and relaxes. You need to make it think "how could each requirement break." The process goes: requirement → boundary → combination → coverage table. Every requirement gets a number. For each one, tests are written at the threshold, just below, and just above. Separate tests cover pairs of requirements that overlap. At the end the agent outputs a table, not a reassurance that "the tests are good." It's like a security guard who only checks the front entrance. The windows, the basement, and the back door stay open. The coverage table forces a walk past every door, not just the front one. An example from the paper: the requirements say "accepts multiple files," but the test feeds in one. A breakage like that goes unnoticed.

Why it works

The agent reads requirements very well. Implementations built from the same specifications passed up to 93% of the reference tests. The problem isn't understanding, it's designing the checks. One of the models wrote about five times fewer tests than the human reference. The agent understands what needs to be done but doesn't think of how to break it. The kicker: when it was also given a working program to check against, test strength barely improved. So a hint about "what's correct" isn't enough. You need an explicit instruction on "what to cover and how." There are three levers with numbers: - A detailed specification. Sol's test strength was 25.5% with a detailed specification and 4.0% with ordinary repository documentation. - Reasoning level. From low to maximum, Sol's test strength rose from 31.3% to 46.5%. The cost per task rose from $0.45 to $2.4. Returns diminish; no miracles. - Specification size. The more requirements, the worse the coverage. Cut a large specification into sections.

When to apply

Development with coding agents → checking and generating tests, especially when you accept work based on an "all tests green" message and don't read the tests yourself. Best suited to command-line utilities and calculation modules with "input → output" logic: rates, discounts, thresholds, rules that overlap. NOT a proven technique for web UIs, databases, and integrations with external services. The authors tested only 165 command-line utilities in Rust, Go, and C/C++. The prompt template itself wasn't tested in the paper; it's assembled from its conclusions.

Mini recipe

1. Number the requirements: R1, R2, R3... If the document doesn't have them, have the agent first break the text into a numbered list. 2. Cut by section: don't feed in a large specification all at once. Ask for tests in parts. 3. Demand tests for every requirement: a comment with the number at the start of each test. That way you can see what covers what. 4. Add boundaries: exactly at the threshold, one unit below, one unit above. 5. Add pairs: tests for combinations of requirements that overlap. Plus the order in which rules apply. 6. Feed lists as lists: if a requirement says "several," the test gets two or three items, not one. 7. Ban self-assessment: have it output a table "requirement → number of tests → combinations," not the words "the tests are good." 8. Break it and check: in a follow-up, ask it to break the code one requirement at a time and show which tests failed. This is our hypothesis; the authors didn't measure it. 9. Don't expect money to work miracles: raise the reasoning level, but remember the diminishing returns.

Examples

[BAD]: `Write tests for the shipping calculator` [GOOD]: `Here is the specification. R1: free shipping on orders of $75+, courier only. R2: for pickup points, a 10% discount on orders of $50+. R3: cash on delivery adds 3% of the total, but no less than $2. R4: when the pickup-point discount and cash on delivery combine, discount first, then the fee. Write the tests in tests/test_delivery.py. Separate tests for each requirement with the number in a comment. Test the boundaries: exactly at the threshold, $1 below and above. Separately, write tests for pairs of requirements and the order from R4. At the end, output a table: requirement, number of tests, combinations covered. Don't tell me the tests are good. Show it in a table.` [BAD]: `All 120 tests passed, so the code is reliable` [GOOD]: `Break exactly one requirement in the code, R3: remove the $2 minimum. Run the tests and show which ones failed. If none failed, write a test for this requirement.`

In plain words

Coding assistants give developers a dangerous illusion of reliability. When you ask a model to write tests from a spec, it optimizes not for finding bugs but for checking the box. You end up with a pretty report where everything is green, but the real value of that pile of checks is a big fat zero. The model dutifully runs the obvious happy path and goes completely blind the moment the logic starts branching.

It's like an inspection by a lazy mechanic: he kicks the tires, wipes the windshield, takes your money, and cheerfully announces the car is in great shape. The engine starts, after all! But the moment you hit the highway and slam the brakes in the rain, the whole system ends up in the ditch. The model only checks that the program moves at all, not where and how it will smash to pieces.

The TestSuiteBench benchmark tested the strength of generated tests under real conditions using mutation testing. The researchers took working code and deliberately broke exactly one requirement from the spec, planting a hidden defect. The result is embarrassing: the best agent caught only 55% of the breakages, and most popular solutions flopped with under 40%. The generated tests happily stayed green on broken code, ignoring critical errors.

They tested on synthetic tasks, but the principle is universal. Take an ordinary shipping calculator: weight, rate zones, a free-shipping threshold of $75, and a cash-on-delivery fee. Ask Claude Code to whip up tests — great coverage, everything passes. But a forgotten discount on the rare "cash on delivery plus pickup point" combination slips right past those tests, and the store covers the difference with the business's real money.

Bottom line: a green light on AI-written autotests is worth jack squat today. Blind trust in AI-generated tests is a ticking time bomb. If you don't want to catch bugs in production, make the model hammer the edge cases, or turn mutation tests loose on the code yourself. Otherwise your software falls apart the first time a user does something unusual.

AI lab assistant

Apply this study to your task

Describe what you're working on. AI takes the method and the measured results from this paper and adapts them to your case, or writes a ready prompt built on them.

Based on TestSuiteBench: green tests from an agent don't prove the code works arXiv:2610.13065

Sign in to apply this study New accounts get 50 free credits.