3,583 papers
arXiv:2610.13065 83 9 окт. 2026 г. FREE

TestSuiteBench: зелёные тесты от агента не доказывают, что код работает

КЛЮЧЕВАЯ СУТЬ
Зелёные тесты от агента почти ничего не доказывают: лучшая модель поймала лишь около 55% намеренных поломок кода, большинство — меньше 40%. Подход из статьи позволяет проверить реальную силу тестов и заставить агента писать проверки по каждому требованию, а не только на основной сценарий. Берёшь рабочий код, ломаешь в нём ровно одно требование и смотришь, упадёт ли хоть один тест. Это называется мутация. Если ничего не упало, тесты пустые, как бы красиво ни выглядел отчёт «все 120 прошли».
Адаптировать под запрос
⚡

TL;DR

Агент для кода пишет много валидных тестов, но слабых. Почти все они проходят на эталонной реализации. Но стоит внести в код ошибку против конкретного требования, и большая часть тестов её не заметит. Исследователи измеряли это через мутации: берут рабочую программу, специально ломают в ней одно требование и смотрят, упадёт ли хоть один тест. Лучший агент поймал только около 55% таких поломок, большинство остальных — меньше 40%.

Главная находка: агент понимает спецификацию, но плохо проектирует проверки. Он пишет тест на основной сценарий и пропускает комбинации входных данных и крайние случаи. Например, проверяет команду с одним файлом, хотя в требованиях сказано «принимает несколько файлов». Тестов при этом получается заметно меньше, чем у человека-эталона: у одной из моделей примерно в пять раз. Дело не в том, что требования непонятны. Когда агенту дали ещё и рабочую программу для сверки, сила тестов почти не изменилась.

Практический вывод: сообщение «все 120 тестов прошли» ничего не говорит о качестве проверки. Тесты нужно требовать по каждому требованию и по комбинациям входов, а их силу проверять поломкой кода. Ещё два рычага, подтверждённые в статье: подробная спецификация и более высокий уровень рассуждений модели.

🔬

Схема метода

Статья — бенчмарк, а не техника. Но её способ проверки силы тестов читатель может повторить вручную:

ШАГ 1: Дать агенту подробную спецификацию (по разделам-требованиям) → набор тестов
ШАГ 2: Прогнать тесты на рабочей версии → доля валидных (V)
ШАГ 3: Сломать код ровно в одном требовании (мутант) → один мутант на требование
ШАГ 4: Прогнать тесты на мутанте → упал хоть один? Да = мутант убит
ШАГ 5: Доля убитых мутантов (M) = реальная сила тестов

Шаги 3–4 можно поручить самому агенту отдельным запросом. Тогда это станет самопроверкой, которую в статье никто не измерял (см. «Адаптации»).

🚀

Пример применения

Задача: Вы руководитель небольшой команды, которая делает калькулятор стоимости доставки для интернет-магазина. Правила тарифа: вес, зона, наложенный платёж, бесплатная доставка от 5 000 ₽, пункты выдачи и курьер. Разработчик с Claude Code написал реализацию и тесты, «все зелёные». Вы хотите убедиться, что тесты поймают ошибку, например забытую скидку при комбинации «наложенный платёж + ПВЗ».

Готового промпта в статье нет. Ниже сборка по её выводам: тесты по каждому требованию, комбинации входов и проверка поломкой.

Промпт:

Ниже спецификация калькулятора доставки. Каждое требование пронумеровано.

[R1] Бесплатная доставка при сумме заказа от 5 000 ₽ — только для курьера.
[R2] Для ПВЗ скидка 10% от тарифа при сумме от 3 000 ₽.
[R3] Наложенный платёж добавляет 3% от суммы заказа, но не менее 50 ₽.
[R4] Вес свыше 20 кг — надбавка 15 ₽ за каждый следующий килограмм.
[R5] Зона 3 (Дальний Восток) — коэффициент 1,8 к базовому тарифу.
[R6] Если сочетаются скидка ПВЗ и наложенный платёж, сначала применяется скидка, потом комиссия.

Напиши тесты в tests/test_delivery.py.

Правила:
1. Для каждого требования — отдельные тесты. В начале каждого теста комментарий с номером требования.
2. Для каждого требования проверь границы: ровно на пороге, на 1 ₽/1 кг ниже и выше.
3. Отдельно напиши тесты на комбинации требований: каждая пара из R1–R6, где они могут пересекаться, и порядок применения из R6.
4. Если в требовании есть список («несколько», «любой из»), подай в тест минимум два-три элемента, а не один.
5. В конце выведи таблицу «требование → сколько тестов → какие комбинации покрыты». Если у требования меньше трёх тестов, объясни почему.

Не говори, что тесты хорошие. Покажи покрытие таблицей.

Результат: Агент вернёт файл с тестами, где у каждого стоит ссылка на требование. В конце будет таблица покрытия: по каждому из R1–R6 видно число тестов и комбинации. Тестов будет заметно больше, чем при обычной просьбе «напиши тесты». Следующим запросом можно попросить агента сломать по одному требованию и показать, какие тесты упали.

🧠

Почему это работает

Слабость LLM. Задача «напиши тесты» кажется агенту выполненной, когда есть набор осмысленных проходящих тестов. Он закрывает основной сценарий и считает дело сделанным. Слабые места лежат на стыках: два файла вместо одного, пороги, порядок применения правил. Проверять их он по умолчанию не стремится.

Сильная сторона. Агент хорошо читает спецификацию. Реализации по тем же спецификациям проходили до 93% эталонных тестов. Если явно указать, что и как покрывать, он может это перечислить и написать.

Как метод это использует. Он заменяет вопрос «хватит ли тестов?» вопросом «что поймает поломку этого требования?». Это превращает размытую цель в проверяемую: у каждого требования должны быть тесты на границы и комбинации.

Рычаги управления: - Детальность спецификации. Самый сильный рычаг в статье. С подробной спецификацией сила тестов у Sol — 25,5%, с обычной документацией репозитория — 4,0%. Чем размытее требования, тем слабее тесты. - Размер спецификации. Чем больше требований, тем хуже агент их покрывает. Режьте большую спецификацию на части и просите тесты по разделам. - Уровень рассуждений. У Sol от низкого к xhigh сила тестов выросла с 31,3% до 46,5%, цена — с $0,45 до $2,4 за задачу. Это отдача с убывающим эффектом, а не чудо. - Количество тестов. Модели с самыми слабыми результатами писали заметно меньше тестов. Требование «минимум N тестов на требование» работает в ту же сторону, но в статье его напрямую не проверяли.

📋

Шаблон промпта

Вот спецификация. Каждое требование пронумеровано.

{спецификация_с_нумерацией_требований}

Напиши тесты в {файл_или_папка_для_тестов}.

Правила:
1. Для каждого требования — отдельные тесты. В начале каждого комментарий с номером требования.
2. Для каждого требования проверь границы: на пороге, чуть ниже, чуть выше.
3. Отдельно напиши тесты на комбинации требований, которые могут пересекаться: {список_пересечений_или_«найди сам»}.
4. Если требование говорит о нескольких значениях ({пример: «несколько файлов», «любой из статусов»}), подай в тест минимум два-три, а не одно.
5. В конце выведи таблицу «требование → число тестов → покрытые комбинации».
   Если у требования меньше {минимум_тестов} тестов, объясни почему.

Не оценивай качество тестов словами. Покажи таблицей.

Подставьте в {спецификация_с_нумерацией_требований} ваши требования с номерами. Если их нет в документе, сначала попросите агента разбить текст на нумерованные требования.

🚀 Быстрый старт — вставь в чат:

Вот шаблон запроса на генерацию тестов. Адаптируй под мою задачу: [твоя задача]. 
Задавай вопросы, чтобы заполнить поля.

[вставить шаблон выше]

LLM спросит, где лежат требования, какие из них могут пересекаться и какие там пороги и списки значений. Это нужно, чтобы правила про границы и комбинации заработали на ваших данных, а не остались общими словами.

⚠️

Ограничения

⚠️ Нет проверенного промпта: Авторы не тестировали, улучшает ли просьба «покрой комбинации» силу тестов. Они измерили проблему и несколько факторов (спецификация, рассуждения, исполняемый эталон). Шаблон выше — наша сборка по их выводам, её нужно проверять на своих задачах.

⚠️ Узкий тип проектов: 165 консольных утилит на Rust, Go и C/C++ с тестами «вход → выход». Веб-интерфейсы, базы данных и интеграции с внешними сервисами не проверяли.

⚠️ Корреляция, не причинность: Модель, которая сама создавала мутанты и запускала программы, писала лучшие тесты. Но модель Sol без этого обошла DeepSeek. Совет «пусть агент сам ломает код» — гипотеза, а не доказанный приём.

⚠️ Дорого и долго: Лучший результат стоил около $10 и 37 минут на задачу. Рост цены даёт всё меньший прирост.

⚠️ Спецификация авторов — не ваша: Их спецификации выросли из эталонных тестов и прошли несколько циклов доработки. Обычное ТЗ почти всегда хуже, и результат будет ближе к 4%, чем к 25%.

⚠️ Правильные спецификации не спасают от слабых тестов: Даже с рабочей программой для сверки сила тестов почти не изменилась. Подробные требования необходимы, но недостаточны.

🔍

Как исследовали

Исследователи из ETH Zurich взяли 165 открытых программ с эталонным кодом и эталонными тестами. Из тестов агент собрал подробную спецификацию, в среднем около 5 000 слов. Затем для каждого требования создали мутанты: копии программы, сломанные ровно в одном месте. Мутанты дорабатывали, чтобы их убивал один тест, а не половина набора. Доля таких мутантов выросла с 32% до 73%.

Спецификации чистили циклами: агенты писали тесты и код по черновику, ошибки разбирали и классифицировали. Если вина лежала на спецификации, её исправляли, пока ошибки из-за неточностей не опустились ниже 5%. Затем шесть современных агентов получили только спецификацию без интернета и должны были написать полный набор тестов.

Сюрприз был в разрыве между показателями. Тесты валидны на 88–96% (кроме двух слабых моделей), реализации по тем же спецификациям проходят до 93% эталонных тестов, а мутанты ловятся лишь на 38–56%. Значит, спецификация понятна и агент её понимает, не хватает именно умения проектировать проверки. Это подтвердили два контрольных опыта. Рабочая программа для сверки подняла валидность тестов с 94,4% до 98,4%, а силу почти не сдвинула (37,7% → 38,1%). Замена спецификации на документацию из репозитория обрушила силу тестов с 25,5% до 4,0%: агент писал на 40% меньше тестов, и они чаще были неверными. Разбор ошибок показал типичный провал: основная функциональность проверена, а комбинации входов и крайние случаи пропущены.

💡

Адаптации и экстраполяции

🔧 Техника: добавить самомутацию → увидеть дыры в тестах сразу

Статья показала, что лучшие модели сами создавали мутанты, но редко: Opus делал это лишь в 33 из 165 задач. Идея в том, чтобы вынести этот шаг в явную инструкцию. Это наша гипотеза, а не проверенный приём:

Теперь возьми по одному требованию из R1–R6. Для каждого сломай код ровно в одном месте, 
не трогая остальное. Запусти тесты. Покажи таблицу: требование → что сломано → упал ли тест 
(какой именно). Если мутант выжил, допиши тест, который его убьёт.

🔧 Техника: разбить спецификацию на части → меньше потерь покрытия

В статье сила тестов падала с ростом числа разделов. Вместо одного запроса на 40 требований дайте агенту по 8–10 требований за раз и проверяйте таблицу покрытия после каждого блока. Это тоже наша гипотеза по их корреляции.

🔗

Ресурсы

  • TestSuiteBench: CodingAgentsStruggle to Generate Strong Test Suites from Specifications (Preprint)
  • Авторы: Kazuki Egashira, Niels Mündler-Sasahara, Martin Vechev (ETH Zurich), Mark Niklas Müller (LogicStar.ai)
  • Сайт: testsuitebench.com
  • Код: github.com/eth-sri/testsuitebench; данные: huggingface.co/collections/eth-sri/testsuitebench
  • Связанные работы: ProgramBench (Yang et al., 2026), SWT-Bench (Mündler et al., 2024), SWE-Mutation (Sun et al., 2026), NL2Repo-Bench (Ding et al., 2025)

📋 Дайджест исследования

Ключевая суть

Зелёные тесты от агента почти ничего не доказывают: лучшая модель поймала лишь около 55% намеренных поломок кода, большинство — меньше 40%. Подход из статьи позволяет проверить реальную силу тестов и заставить агента писать проверки по каждому требованию, а не только на основной сценарий. Берёшь рабочий код, ломаешь в нём ровно одно требование и смотришь, упадёт ли хоть один тест. Это называется мутация. Если ничего не упало, тесты пустые, как бы красиво ни выглядел отчёт «все 120 прошли».

Принцип работы

Агент проверяет «работает ли основной путь» и успокаивается. Нужно заставить его думать «чем сломать каждое требование». Процесс такой: требование → граница → комбинация → таблица покрытия. Каждое требование получает номер. На каждое пишутся тесты на пороге, чуть ниже и чуть выше. Отдельно идут тесты на пары требований, которые пересекаются. В конце агент выдаёт таблицу, а не заверение «тесты хорошие». Это как охранник, который проверяет только главный вход. Окна, подвал и чёрный ход остаются открытыми. Таблица покрытия заставляет обойти все двери, а не только парадную. Пример из статьи: в требованиях «принимает несколько файлов», а тест подаёт один. Такая поломка проходит незамеченной.

Почему работает

Агент отлично читает требования. Реализации по тем же спецификациям проходили до 93% эталонных тестов. Проблема не в понимании, а в проектировании проверок. У одной из моделей тестов примерно в пять раз меньше, чем у человека-эталона. Агент понимает, что нужно сделать, но не додумывается, как это сломать. Жесть: когда ему дали ещё и рабочую программу для сверки, сила тестов почти не выросла. Значит, подсказки «что правильно» мало. Нужна явная инструкция «что и как покрыть». Есть три рычага с цифрами: - Подробная спецификация. У модели Sol сила тестов 25,5% с детальной спецификацией и 4,0% с обычной документацией репозитория. - Уровень рассуждений. От низкого до максимального сила тестов у Sol выросла с 31,3% до 46,5%. Цена за задачу выросла с $0,45 до $2,4. Отдача падает, чудес нет. - Размер спецификации. Чем больше требований, тем хуже покрытие. Режь большую спецификацию на разделы.

Когда применять

Разработка с агентами для кода → проверка и генерация тестов, особенно когда вы принимаете работу по сообщению «все тесты зелёные» и не читаете сами тесты. Лучше всего подходит для консольных утилит и расчётных модулей с логикой «вход → выход»: тарифы, скидки, пороги, правила, которые пересекаются. НЕ подходит как доказанный приём для веб-интерфейсов, баз данных и интеграций с внешними сервисами. Авторы проверяли только 165 консольных утилит на Rust, Go и C/C++. Сам шаблон промпта в статье не тестировали, это сборка по её выводам.

Мини-рецепт

1. Пронумеруй требования: R1, R2, R3... Если в документе их нет, пусть агент сначала разобьёт текст на нумерованный список.
2. Режь по разделам: большую спецификацию не скармливай целиком. Тесты просишь по частям.
3. Потребуй тесты на каждое требование: в начале теста комментарий с номером. Так видно, кто за что отвечает.
4. Добавь границы: ровно на пороге, на единицу ниже, на единицу выше.
5. Добавь пары: тесты на комбинации требований, которые пересекаются. Плюс порядок применения правил.
6. Списки подавай списками: если в требовании «несколько», в тест идут два-три элемента, не один.
7. Запрети самооценку: пусть выдаст таблицу «требование → число тестов → комбинации», а не слова «тесты хорошие».
8. Сломай и проверь: следующим запросом попроси сломать код по одному требованию и показать, какие тесты упали. Это наша гипотеза, авторы её не измеряли.
9. Не жди чуда от денег: повышай уровень рассуждений, но помни про убывающую отдачу.

Примеры

[ПЛОХО]: `Напиши тесты для калькулятора доставки` [ХОРОШО]: `Вот спецификация. R1: бесплатная доставка от 5 000 ₽ только для курьера. R2: для пункта выдачи скидка 10% при сумме от 3 000 ₽. R3: наложенный платёж добавляет 3% от суммы, но не менее 50 ₽. R4: при сочетании скидки пункта выдачи и наложенного платежа сначала скидка, потом комиссия. Напиши тесты в tests/test_delivery.py. Для каждого требования отдельные тесты с номером в комментарии. Проверь границы: ровно на пороге, на 1 ₽ ниже и выше. Отдельно напиши тесты на пары требований и порядок из R4. В конце выведи таблицу: требование, число тестов, покрытые комбинации. Не говори, что тесты хорошие. Покажи таблицей.` [ПЛОХО]: `Все 120 тестов прошли, значит, код надёжный` [ХОРОШО]: `Сломай в коде ровно одно требование, R3: убери минимум 50 ₽. Запусти тесты и покажи, какие упали. Если не упал ни один, допиши тест на это требование.`
Источник: TestSuiteBench: Coding Agents Struggle to Generate Strong Test Suites from Specifications
ArXiv ID: 2610.13065 | Сгенерировано: 2026-10-12 05:20

Проблемы LLM

ПроблемаСутьКак обойти
Агент пишет много тестов, но они слабые. Все зелёные, а ошибки не ловятПросишь "напиши тесты по спецификации". Получаешь десятки осмысленных тестов. Все проходят на правильном коде. Но если сломать код по одному требованию, большинство тестов этого не заметит. Агент покрывает основной сценарий и считает работу сделанной. Границы и комбинации входов он пропускает. Например, проверяет один файл, хотя в требовании "несколько файлов". Причём требования агент понимает. Слабое место — не чтение, а выбор того, что проверять. Сообщение "все тесты прошли" ничего не говорит о качествеЗадай структуру проверок явно. Пронумеруй требования. Попроси отдельные тесты на каждое. Попроси границы: на пороге, чуть ниже, чуть выше. Попроси комбинации требований, которые пересекаются. Для списков ("несколько", "любой из") требуй два-три элемента. В конце пусть выведет таблицу: требование → число тестов → какие комбинации покрыты. Не принимай оценку словами вроде "тесты полные". Важно: надёжно подтверждено только одно. Подробная спецификация сильно улучшает тесты. Остальные приёмы логичны, но не проверены. Проверяй их поломкой кода (см. метод ниже)

Методы

МетодСуть
Проверка тестов поломкой — настоящая сила тестов вместо "всё зелёное"Тест полезен, только если он может упасть на ошибке. Проходящий тест на правильном коде этого не доказывает. Шаги: 1) Возьми рабочий код и тесты. Все проходят. 2) Сломай код ровно в одном требовании. Например, убери скидку при сочетании двух условий. 3) Запусти тесты. 4) Упал хоть один — поломку ловят. Не упал — в тестах дыра. 5) Повтори для каждого требования. Доля пойманных поломок — это реальная сила набора. Почему работает: вопрос "хватит ли тестов?" размытый. Вопрос "что поймает поломку этого требования?" проверяемый. Когда да: есть чёткие требования, вход → результат, код запускается из консоли или как функция. Когда нет: веб-интерфейсы, базы данных, интеграции с внешними сервисами. Там поломку сложнее задать. Оговорка: поломки можно поручить самой модели отдельным запросом. Но что это улучшит тесты, не доказано. Это гипотеза
📖 Простыми словами

TestSuiteBench: CodingAgentsStruggle to Generate Strong Test Suites from Specifications

arXiv: 2610.13065

Кодинг-ассистенты создают для разработчиков опасную иллюзию надёжности. Когда ты просишь модель написать тесты по ТЗ, она оптимизирует не поиск багов, а галочку выполнения. В итоге получаешь красивый отчёт, где всё зелёное, но реальная ценность этой пачки проверок — полный пшик. Нейросеть добросовестно прогоняет очевидный базовый сценарий и наглухо слепнет, как только логика начинает ветвиться.

Это как техосмотр у ленивого автомеханика: он попинал колёса, протёр лобовое стекло, взял деньги и бодро заявил, что тачка огонь. Двигатель ведь заводится! Но стоит тебе выехать на трассу и в дождь резко нажать тормоз — система летит в кювет. Модель проверяет лишь то, что программа в принципе шевелится, а не то, где и как она разобьётся в щепки.

В бенчмарке TestSuiteBench силу сгенерированных тестов проверили в боевых условиях через мутационное тестирование. Исследователи брали рабочий код и намеренно ломали ровно одно требование из спеки, создавая скрытый дефект. Результат — позорный: лучший агент поймал только 55% поломок, а большинство популярных решений слились с цифрой меньше 40%. Сгенерированные тесты радостно продолжали быть зелёными на сломанном коде, игнорируя критические ошибки.

Тестировали на синтетических задачах, но принцип универсален. Возьми обычный калькулятор доставки: вес, тарифные зоны, бесплатный порог от 5 000 ₽ и комиссия за наложенный платёж. Просишь Claude Code набросать тесты — покрытие отличное, всё проходит. Но забытую скидку при редком сочетании «наложенный платёж плюс пункт выдачи» эти тесты проморгают, а разницу магазин покроет живыми деньгами бизнеса.

Короче: зелёный цвет автотестов от нейросети сегодня не стоит нихера. Слепое доверие тестам от AI — это мина замедленного действия. Если не хочешь ловить баги в продакшене, заставляй модель долбить пограничные случаи или сам натравливай на код мутационные тесты. Иначе твой софт развалится при первой же нестандартной ситуации у пользователя.

Работа с исследованием

Адаптируйте исследование под ваши задачи или создайте готовый промпт на основе техник из исследования.

0 / 2000
~0.5-2 N-токенов ~10-30с
~0.3-1 N-токенов ~5-15с