Как заставить ИИ писать полезные тесты: простое руководство
Попросили ChatGPT написать тесты — получили десяток проверок. Всё зелёное, покрытие выросло. Радуетесь? Рано. Скорее всего, эти тесты бесполезны.
Запустите мутационное тестирование — измените в коде оператор сравнения, поменяйте константу, уберите проверку. Тесты остались зелёными? Вот и ответ. Проверки есть, но они ничего не ловят.
Проблема не в ИИ, а в том, как мы его используем. Разберёмся, что делать правильно.
Шаг 1: Сначала контракт, потом код
Не давайте ИИ код сразу. Сначала опишите, что функция должна делать.
Для API — используйте OpenAPI-схему. Перечислите эндпоинты, статус-коды, структуры данных, возможные ошибки.
Для функций — опишите типы параметров, что возвращает, какие исключения выбрасывает, какие граничные случаи должны обрабатываться.
Пример плохого промпта:
Напиши тесты для этой функции [вставил код]
Пример хорошего промпта:
Функция parseDate принимает строку и возвращает Date. Валидные форматы: "YYYY-MM-DD", "DD.MM.YYYY", "MM/DD/YYYY". При невалидном формате выбрасывает ParseError. При null/undefined выбрасывает ArgumentError. Должна корректно обрабатывать високосные годы. Напиши тесты с таблицей входов и ожидаемых результатов.
Видите разницу? Во втором случае ИИ знает, что именно проверять.
Шаг 2: Требуйте table-driven структуру
Не просите «напиши 10 тестов». Просите таблицу.
Создай таблицу с колонками: - Входные данные - Ожидаемый результат - Описание случая - Ожидаемая ошибка (если есть) Включи: - 3-4 позитивных сценария - Все граничные случаи (пустая строка, null, максимальная длина) - Негативные сценарии (невалидные форматы, некорректные типы)
Почему таблица? Потому что она заставляет думать систематически. Сразу видно, что забыли проверить пустой ввод или максимальное значение.
Добавлять новый кейс — значит добавить строку. Код компактный, читаемый, легко расширяется.
Шаг 3: Итерируйте — не пытайтесь всё за раз
Генерация за один запрос не работает. Нужны циклы.
Первый запрос: позитивные сценарии для штатных случаев. Запускаете, проверяете, что тесты проходят.
Второй запрос: негативные сценарии.
Добавь тесты для:
- Невалидных входов (некорректный формат, неверный тип)
- Граничных значений (null, пустая строка, максимальная длина)
- Отсутствующих обязательных полей
- Проверки сообщений об ошибках
Третий запрос: смотрите отчёт покрытия, находите непокрытые ветви.
В функции есть проверка if (value < 0). Сгенерируй тест, который пройдёт через эту ветвь.
Каждый раз — запуск, проверка, уточнение. Не накапливайте большие пачки непроверенного кода.
Подробнее про решение сложных задач с ИИ я писал в этом посте
Table-driven структура: систематичность против хаоса
Когда всё же нужны конкретные примеры, table-driven подход превращает набор тестов из свалки в систему. Вместо десятка отдельных функций — одна параметризованная с таблицей входов и ожидаемых результатов.
Просите ИИ сразу генерировать такую структуру. Колонки: входные параметры, ожидаемый выход, описание кейса, ожидаемая ошибка (если есть). Строки — конкретные сценарии. Такой формат заставляет думать систематически: сразу видно, что не хватает граничного значения или негативного сценария.
Преимущество очевидно — добавить новый кейс означает добавить строку в таблицу, а не копировать функцию целиком. Код компактный, читаемый, легко рефакторится. Но главное — таблица помогает выявить классы эквивалентности входов и осознанно выбрать представителей каждого класса.
Чек-лист перед принятием теста
Каждый сгенерированный тест должен пройти три проверки:
1. Запуск Тест стабильно проходит локально и в CI. Нет зависимостей от времени выполнения, порядка тестов, случайных данных.
2. Читаемость За 30 секунд понятно, что проверяет тест. Структура AAA (Arrange-Act-Assert) очевидна. Имена говорящие.
3. Ценность Тест ловит реальные баги. Проверьте мутационным тестированием — если mutation score низкий, ассерты слишком слабые.
Храните промпты как инфраструктуру
Когда находите промпт, который хорошо работает — сохраняйте его в репозиторий. Создайте папку docs/prompts/ или .ai-templates/. Складывайте туда шаблоны запросов: для генерации table-driven тестов, для property-based свойств, для метаморфных отношений, для проверок исключений.
По мере накопления опыта обновляйте шаблоны. Добавляйте примеры хороших и плохих результатов. Указывайте типичные ошибки и как их избегать. Это превращает хаотичный процесс в воспроизводимую практику.
Логируйте траекторию улучшений при итеративной генерации. Сохраняйте артефакты: отчёты покрытия, результаты мутационного тестирования, метрики качества. Прозрачность процесса критична для доверия команды.
Главное
ИИ не пишет тесты за вас. Он генерирует черновики. Ваша задача — проверить, что эти черновики действительно ловят баги.
Начинайте с описания контракта, а не кода. Требуйте table-driven структуру. Итерируйте короткими циклами. Проверяйте силу тестов мутационным анализом. Сохраняйте работающие промпты.
Автогенерированные тесты без критического анализа — это иллюзия защиты, хуже чем её отсутствие. Но правильно используя ИИ, можно значительно повысить качество покрытия при меньших затратах времени.
Подробнее об ИИ инструментах, которые позволили попасть в топ 5% лучших сотрудников Яндекса, рассказываю тут: