Автогенерация тестов с Claude Code: какие юнит и интеграционные тесты просить, как фиксировать границы и быстро оценивать качество еще до CI.

Обычно боль простая: тестов нет, релиз близко, и любое небольшое изменение превращается в лотерею. Руки тянутся попросить ИИ: «покрой все тестами», чтобы быстро закрыть пробел.
Но автогенерация часто дает много строк и мало уверенности. Появляются тесты, которые повторяют реализацию, проверяют «что метод вызвался», завязаны на случайные детали или ломаются от любого рефакторинга. Формально покрытие растет, а риск багов почти не падает.
Если говорить честно, «экономит время» - это не количество файлов. Это когда вы меньше тратите времени на однообразную подготовку данных, быстрее ловите регрессии до ручной проверки и спокойно меняете код, потому что тесты проверяют поведение, а не внутренности.
Поэтому цель автогенерации тестов с Claude Code - получить небольшой набор проверок, которые защищают важные сценарии и дают понятный сигнал, когда поведение сломалось.
Есть ситуации, когда начинать с генерации не стоит. Если нет хотя бы минимальной спецификации (что должно происходить на входах и выходах), ИИ будет угадывать, и тесты закрепят случайные решения. Если в коде хаос: смешаны бизнес-правила и инфраструктура, нет явных границ, много скрытых зависимостей, то тесты будут либо «хрупкими», либо пустыми.
Практичный ориентир: сначала описываете 3-5 ключевых сценариев (включая негативные), фиксируете ожидаемый результат простыми словами, и только потом просите генерацию. Так вы получаете не «много тестов», а быстрый способ вернуть контроль над изменениями.
Юнит тесты проверяют маленький кусок логики в изоляции: одну функцию, метод, правило расчета. Их задача - быстро ловить ошибки в бизнес-правилах и граничных случаях, не трогая сеть и базу.
Интеграционные тесты проверяют, что части системы реально работают вместе: код плюс база, код плюс HTTP-слой, код плюс очередь. Они медленнее и сложнее, зато находят ошибки в конфигурации, SQL, сериализации и обработке ошибок.
Часто советуют 70/30 (юнит/интеграционные), но это не закон. Пропорция зависит от того, что чаще ломается.
Если просите автогенерацию тестов с Claude Code, заранее укажите целевую долю. Иначе модель легко «завалит» проект десятками юнитов там, где важнее проверить связку с БД.
Юнитами выгодно покрывать чистую бизнес-логику: валидации, расчеты, преобразования, правила доступа, выбор веток по статусам. Например, в Go-сервисе можно юнитами проверить, как собирается SQL-запрос или как считается стоимость заказа, а доступ к PostgreSQL заменить заглушкой.
Интеграционным тестам оставьте то, что ломается на стыках: реальные запросы к PostgreSQL, обработку транзакций, HTTP-обработчики и сериализацию JSON, работу с внешними сервисами и очередями (хотя бы через тестовый стенд или контейнер).
Важно не перепутать интеграционные и E2E. Интеграционный тест обычно проверяет один сервис и его зависимости (например, сервис + БД). E2E проверяет пользовательский сценарий целиком через UI и несколько сервисов. Если вам не нужны E2E, так и пишите: «без UI и без прогонки полного пользовательского пути».
Генерация тестов лучше всего работает, когда вы заранее задаете границы. Иначе модель начнет угадывать архитектуру, тянуть в тесты лишние детали и плодить моки без смысла.
Первый шаг - назвать SUT (system under test): что именно проверяем. Это может быть одна функция, сервисный метод или use case. Чем точнее объект, тем проще понять, какие сценарии нужны и какие зависимости вообще имеют право появиться в тестах.
Дальше перечислите зависимости и решите, что мокируем, а что оставляем реальным. Хорошее правило: мокируем то, что делает тест медленным или нестабильным (сеть, внешние API, время), а реальным оставляем то, что формирует логику внутри модуля.
Отдельно фиксируйте контракт входов и выходов. Это не только «счастливый путь», но и ошибки, пустые значения, границы диапазонов, дубликаты, отсутствие прав. Если контракт не записан, тесты почти всегда получаются поверхностными и часто проверяют только «не упало».
Полезно заранее сказать, что считается «не тестируем». Например: логирование, внутренние детали фреймворка, формат UI-отступов, конфигурация DI-контейнера, точные тексты технических сообщений (если они не часть контракта).
Перед генерацией добавьте 5-10 строк правил. Пример, который можно копировать и править под задачу:
createOrder() сервиса заказов; тестируем бизнес-правила, не контроллер.PaymentGateway, мок EmailSender, реальная валидация входа.orderId или ошибка.Короткий пример: если SUT - расчет скидки, явно запретите тестировать округление «как в UI» и разрешите проверять только финальную сумму и причины отказа. Тогда тесты будут про правила, а не про оформление.
Автогенерация тестов с Claude Code лучше всего работает, когда вы не просите «напиши тесты», а задаете рамки: что именно тестируем, какие правила важны, и как вы поймете, что тесты получились нормальными. Тогда модель меньше выдумывает поведение и не плодит бесполезные проверки.
Дайте минимальный контекст, без которого тесты будут гаданием: сигнатуры функций и публичных методов, примеры входов и ожидаемых выходов, важные бизнес-правила (в одну-две строки каждое), а также список зависимостей, которые можно мокать. Если есть пограничные условия (пустая строка, 0, отрицательные числа, слишком длинные значения) - перечислите их явно.
Отдельно попросите стиль тестов. Это кажется мелочью, но сильно влияет на читаемость и поддержку:
Негативные кейсы нужно просить прямо: какие ошибки ожидаются, какой тип/текст/код ошибки важен, и что должно происходить с состоянием (ничего не записывать, не менять, не отправлять). Если в проекте приняты свои ошибки или коды, перечислите их.
Чтобы не получить копипасту, просите параметризацию: «сделай таблицу входов и ожиданий и оформи параметризованный тест». Это особенно полезно для валидаций и правил расчета.
Хороший прием - сначала запросить список тест-кейсов, а уже потом код. Например:
Сначала составь список тест-кейсов (без кода) для функции CreateOrder(input). Укажи: название кейса, вход, ожидаемый результат/ошибка, что мокать. После того как я подтвержу список, сгенерируй тесты в стиле Arrange-Act-Assert, с читаемыми именами, один смысл на тест, и где уместно - параметризованные тесты.
Вот сигнатура и правила: ...
Примеры входов/выходов: ...
Негативные сценарии обязательны: ...
Так вы сначала проверяете логику покрытия, и только затем тратите время на код тестов.
Если вы хотите, чтобы автогенерация тестов с Claude Code давала пользу, а не просто пачку файлов, просите результат в два прохода: сначала кейсы, потом код. Так вы быстрее ловите пропуски и лишнее, не читая десятки строк.
Сначала попросите перечень сценариев и только после согласования - реализацию.
Сгенерируй тест-план для функции/модуля cИМЯe.
Формат: список кейсов (название, входные данные, ожидание) + отдельный блок «что НЕ тестируем».
После списка задай 3 вопроса, если есть неопределенности.
Код тестов пока не пиши.
После того как вы поправили план, второй запрос:
Теперь по согласованному тест-плану сгенерируй код тестов.
Требования: читаемые имена тестов, минимум флака, без лишних моков.
Этот формат помогает зафиксировать, что является предметом теста, а что подменяем.
Пишем тесты для cИМЯe.
Границы:
- Тестируем только: cсписокe
- Не тестируем: cсписокe
Зависимости:
- Мокать: cчто и почемуe
- Не мокать: cчто должно быть реальнымe
Выход: сначала 8-12 тест-кейсов, потом код.
Удобно, когда поведение можно описать таблицей.
Сгенерируй набор тестов по контракту.
Сначала составь таблицу:
| Сценарий | Вход | Ожидание | Ошибка/исключение |
Заполни минимум 10 строк, включая 3 негативных.
После моего «ОК» сгенерируй код тестов строго по таблице.
Хорошие тесты обычно короче, чем первый черновик.
Отрефактори сгенерированные тесты:
- Убери дубли, сгруппируй по поведению
- Переименуй тесты так, чтобы читались как требования
- Оставь комментарии только там, где без них не понять смысл
Покажи дифф или перечисли точные правки.
Чтобы комментариев не стало слишком много, уточняйте правило: «комментарий только если объясняет бизнес-смысл или неочевидную причину мока; не комментировать очевидные шаги».
Самый быстрый путь к нормальным тестам начинается не с генерации, а с коротких правил поведения. Выберите один небольшой модуль (один файл или один сервис) и запишите 5-7 правил простыми словами: что должно происходить, что не должно, какие ошибки ожидаем, какие входные данные считаем валидными.
Дальше включайте автогенерацию тестов с Claude Code, но сначала просите не код, а набор кейсов. Пусть ИИ предложит сценарии и ожидаемые результаты, а вы быстро отметите лишнее, добавите пропущенное и уточните крайние случаи. Это занимает минуты и экономит часы переделок.
После согласования кейсов зафиксируйте границы: где будут моки, а где реальные зависимости. Для юнит-тестов обычно договариваются, что сеть и база не трогаются, а время и рандом стабилизируются. Для интеграционных тестов решите, какие данные нужны, как их готовить и что важно проверять (контракт ответа, миграции, транзакции), а что не важно (внутренние детали реализации).
Держите процесс простым и повторяемым:
Только после локального прогона имеет смысл коммитить и запускать CI. Если тесты падают на вашей машине, в CI они просто потратят время команды и замаскируют реальные проблемы в коде.
Автогенерация тестов с Claude Code экономит время только если тесты реально ловят поломки, а не создают видимость активности. До запуска CI можно за 10-15 минут понять, что набор стоит оставлять, а что лучше перепросить.
Задайте простой вопрос: что сломается в продукте, если этот тест начнет падать? Хороший тест защищает договоренность (контракт) функции или API: правильный результат, корректная ошибка, нужный статус, сохранение данных.
Плохие сигналы обычно видны сразу: тесты повторяют внутренние шаги реализации, слишком много моков ради того, чтобы тест вообще запустился, и почти нет проверок результата (assert есть, но он про «не упало» или «вызвалось»). Такие тесты хрупкие: малейший рефакторинг и все красное, хотя поведение не менялось.
Сделайте короткую серию проверок, не дожидаясь CI:
> на >=, инвертируйте условие, уберите обработку ошибки. Хотя бы один тест должен упасть.Пример: если у вас есть функция расчета скидки, тест должен падать, когда вы меняете правило округления или убираете проверку отрицательной суммы. Если он падает только из-за переименования переменной - перепросите генерацию и уточните, что тестируем именно входы/выходы и ошибки.
Самая частая проблема в том, что автогенерация тестов с Claude Code начинается с просьбы «покрой все». В ответ вы получаете много файлов, но половина из них тестирует не то, что важно, а вторая половина ломается при любом рефакторинге.
Если не сказать, что именно считается внешними зависимостями (БД, сеть, время, файловая система), модель начнет мокать все подряд. В итоге тесты проверяют, как вы замокали моки, а не поведение кода.
Часто «юнит» тест внезапно поднимает реальную базу, читает конфиги, зависит от миграций и случайного порядка данных. Такой тест медленный и хрупкий, а диагностика проблем в нем плохая.
ИИ легко цепляется за внутренние функции, приватные поля, точные SQL-строки или порядок вызовов. Это делает тесты заложниками текущей реализации. Правильнее проверять входы и выходы: результат, ошибки, побочные эффекты, события.
Автогенерация часто покрывает «счастливый путь», но пропускает пустые значения, null, дубликаты, переполнение, таймауты, повторы запросов, частичные ответы. А именно там живут реальные баги.
Тесты иногда сравнивают точные структуры, которые случайно совпали сегодня (порядок элементов, конкретные ID, формат даты), хотя контракт требует только часть полей или не фиксирует порядок.
Чтобы быстро поймать эти ошибки, держите в голове вопрос: «Если я завтра переименую переменную, поменяю внутреннюю реализацию или порядок запросов, должен ли тест упасть?» Например, для функции создания пользователя тест должен падать, если нарушен контракт (нельзя создать дубликат email), но не должен падать, если вы поменяли ORM или оптимизировали запрос.
Короткое правило: просите у ИИ тесты на поведение и контракты, а границы зависимостей фиксируйте заранее одним абзацем в промпте.
Перед коммитом важно убедиться, что автогенерация тестов с Claude Code дала не просто пачку файлов, а набор проверок, которым вы будете доверять через месяц.
Пробегитесь глазами и проверьте:
Если что-то не проходит, лучше поправить сразу, пока контекст свежий. Например, если тест для Go-сервиса внезапно поднимает реальную PostgreSQL, а вы хотели юнит, это не мелочь: такие тесты будут флапать и тормозить.
Три правки, которые часто спасают набор: переименовать тесты так, чтобы они читались как фразы; убрать случайность (фиксировать время, UUID, порядок, сид для генераторов); разделить один большой тест на 2-3 маленьких, если он проверяет разные причины падения.
Финальная проверка простая: сможете ли вы по названиям тестов восстановить требования к функции? Если нет, тесты стоит упростить.
Представьте сервис оформления заказа с расчетом скидки. Правила простые, но в них легко ошибиться: (1) скидка 10% для заказов от 3000, (2) скидка 15% для пользователей со статусом VIP, (3) скидка не больше 500 рублей, (4) итоговая сумма округляется до рубля.
Для автогенерации тестов с Claude Code заранее зафиксируйте границы. Мы тестируем расчет скидки и запись заказа. Платежный провайдер не трогаем, его мокируем. База данных в интеграционных тестах реальная (тестовая), потому что нас интересуют транзакции и конфликты.
Вот короткий запрос, который обычно дает адекватный результат:
Сгенерируй тесты для сервиса OrderService.
Контекст: Go, PostgreSQL. Функция CalculateDiscount(total, isVIP) -> discount, finalTotal.
Правила: 10% от 3000+, 15% для VIP, максимум 500 руб, округление finalTotal до рубля.
Нужно:
- Юнит-тесты только для CalculateDiscount: таблица кейсов, отдельные проверки округления и лимита 500.
- Интеграционные тесты для CreateOrder: запись в БД в транзакции, обработка конфликта (повторный orderId), откат при ошибке.
Границы: платежный клиент мок, внешние HTTP не вызывать.
Выведи: названия тестов, данные, ожидания, и почему каждый тест нужен.
Что особенно стоит просить, чтобы тесты были полезными:
Дальше быстрый способ оценить качество до CI - вручную «сломать» код и посмотреть, падают ли тесты по делу. Сделайте 1-2 правки:
Если тесты не упали, значит они проверяют не то (или проверок мало). Если упали, но сообщение непонятное, попросите ИИ улучшить названия кейсов и тексты ошибок, чтобы причина была видна сразу.
Когда первые тесты начали приносить пользу, превратите автогенерацию в повторяемый ритуал. Иначе она быстро скатится в «периодические подвиги» и будет разваливаться при каждом новом участнике команды.
Соберите короткий шаблон, который вы копируете в каждый запрос: что именно тестируем, где границы ответственности, какие зависимости можно мокать, и какие правила оформления нужны (названия тестов, структура файлов, стиль ассертов). Чем стабильнее этот шаблон, тем меньше «угадываний» и тем меньше правок руками.
Начните с одного модуля. Выберите участок, где часто бывают регрессии (например, расчеты цен, права доступа, форматирование данных), и доведите процесс до привычки: запрос -> проверка качества до CI -> правки -> коммит.
Полезно договориться, что считается «хорошим тестом». Достаточно простого стандарта, который легко проверить глазами:
После этого добавьте легкий контроль качества: один человек в команде быстро просматривает новые тесты на соответствие стандарту, до того как они станут шумом в репозитории.
Удобно сначала зафиксировать требования и границы в Planning Mode, а уже потом генерировать тесты по этому плану. Для безопасных итераций используйте snapshots и rollback: можно попробовать разные варианты тестов и откатиться, если набор стал хуже.
Когда тесты стабилизировались и вы понимаете, что именно должно проверяться, подумайте про экспорт исходников и дальнейший привычный процесс разработки. Если вы собираете продукт через TakProsto (takprosto.ai), этот подход хорошо ложится на работу маленькими итерациями: уточнили контракт -> обновили тесты -> проверили ключевые интеграции.
Начните со списка из 3–5 ключевых сценариев (включая негативные) и ожидаемых результатов простыми словами. Потом попросите ИИ сначала выдать тест-кейсы без кода, согласуйте их и только затем генерируйте код.
Так вы получаете проверки, которые защищают поведение, а не «покрытие ради покрытия».
Вам нужна хотя бы минимальная спецификация:
Без этого ИИ начнет угадывать и закрепит случайные решения тестами.
По умолчанию:
Если у вас много «проводов» (БД, авторизация, внешние API), смещайтесь к большему числу интеграционных. Если много вычислений и правил — к юнитам.
Ориентир:
В промпте прямо укажите целевую долю, иначе модель может «завалить» проект сотнями юнитов там, где важнее проверить БД и контракты.
Сформулируйте SUT (system under test) одним предложением:
createOrder() сервиса заказов; тестируем бизнес-правила, не контроллер».Дальше перечислите зависимости и решите:
Чем яснее границы, тем меньше бессмысленных моков и «хрупких» тестов.
Пишите промпт так, чтобы сначала был тест-план, потом код:
Это резко снижает шанс получить копипасту и проверки «не упало».
Просите негативные кейсы явно и конкретно:
Если негативные сценарии не попросить, модель часто ограничится «счастливым путем».
Не просите E2E, если они не нужны. Зафиксируйте:
Прямо напишите в требованиях: «без UI и без прогона полного пользовательского сценария».
Сделайте быстрые проверки за 10–15 минут:
> на >=, инвертируйте условие) — хотя бы один тест должен упасть;Если тесты падают от рефакторинга, они завязаны на реализацию, а не на поведение.
Самые частые проблемы:
Лечится одним приемом: фиксируйте SUT, зависимости и контракт вход/выход в промпте и просите сначала тест-кейсы, потом код.