Тесты и документация — две вещи, которые разработчик пишет в последнюю очередь и часто пропускает. ИИ решает 80% этой рутины: дать ему функцию — получить набор unit-тестов с покрытием happy path и edge cases. Дать модуль — получить README с понятными примерами. Финальная вычитка остаётся за вами, но time-to-write падает в 5–10 раз.
Внутри — 7 шаблонов: mutation testing, интеграционные тесты, snapshot-тесты для UI, моки внешних сервисов, README проекта, API-документация (OpenAPI), комментарии и docstrings к сложному коду.
Главное правило: не доверяй сгенерированным тестам без проверки. ИИ может написать тест, который проходит, но проверяет не то поведение. Пример: тест на «сохранение пользователя» проверяет, что метод не падает, но не проверяет, что данные реально записаны в БД. Прочитайте каждый ассерт глазами — и только тогда мерджите.
🧬 Mutation testing — проверка качества тестов
Я хочу проверить качество существующих unit-тестов через mutation testing. Что это: инструмент намеренно вносит маленькие правки в код (мутации — заменить `>` на `>=`, `&&` на `||`, удалить return и т.п.) и проверяет, поймают ли это ваши тесты. Если мутация не убита тестом — у вас слепое пятно в покрытии. Контекст: Стек: [язык / фреймворк / тестовый раннер]. Mutation tool: [Stryker для JS/TS / mutmut для Python / PIT для Java / Stryker.NET для .NET]. Модуль для проверки: [путь]. Что нужно: 1) Команда запуска mutation testing с оптимальной конфигурацией для моего стека. 2) Как читать отчёт — какие категории мутаций критичные (boundary, conditional, return), а какие можно игнорировать (мутации в logging-вызовах). 3) Целевой mutation score — 75–85% для продуктового кода, 90%+ для критичной бизнес-логики. 4) Стратегия закрытия слепых пятен — для каждой выжившей мутации показать, какой тест её должен был поймать и почему не поймал. Запрет: - Гнаться за 100% mutation score — последние 5–10% обычно — equivalent mutants, которые невозможно убить без убийства бизнес-смысла. - Запускать mutation testing на полном репозитории при первом проходе — стартуй с одного критичного модуля. - Игнорировать выжившие мутации в utility-функциях, которые «вроде покрыты» — часто именно там прячется ложное чувство защищённости. Модуль и его текущие тесты: ``` [ВСТАВЬ_МОДУЛЬ_И_ТЕСТЫ] ```
Mutation testing — следующий шаг после обычного coverage. Coverage 95% говорит «ваш код выполнялся в тестах», mutation score 80% говорит «ваши тесты реально поймают баги». Это две разные метрики, и первая часто врёт. Equivalent mutants (семантически идентичные оригиналу мутации) — причина, по которой 100% mutation score недостижим: например, замена `i++` на `++i` в for-loop часто эквивалентна, и тест это не отличит.
🔗 Интеграционные тесты
Напиши интеграционные тесты для endpoint / сценария: [ОПИШИ_СЦЕНАРИЙ — например: «POST /api/orders создаёт заказ, списывает товар со склада, отправляет email подтверждения»]. Стек: [язык / фреймворк / БД / тестовый framework]. Окружение: [docker-compose с тестовой БД / in-memory БД / staging]. Покрой: 1) Happy path — полный сценарий, проверка результатов в БД и побочных эффектов (email, запись в таблицу). 2) Идемпотентность — что будет при повторе того же запроса. 3) Откат при ошибке — если на шаге 2 ошибка, результаты шага 1 откатились. 4) Конкурентный доступ — что если две параллельные операции на один и тот же ресурс. 5) Авторизация — что без auth / с чужим токеном. Принципы: - Каждый тест начинается с чистого state (setUp / fixture). - Реальная БД, не моки (это integration, не unit). - Проверка не только HTTP-ответа, но и состояния БД. - Внешние API (платёжки, sms) — мокаем, не дёргаем реально. Сценарий: [ВСТАВЬ_СЦЕНАРИЙ_ИЛИ_КОД]
Тест на откат при ошибке (rollback) — самый часто пропускаемый и самый ценный. Большинство багов в продакшене — не «функция упала», а «функция упала на середине, оставив данные в несогласованном состоянии». Без явного теста rollback вы это найдёте только в проде на реальных деньгах.
📸 Snapshot-тесты для UI-компонента
Напиши snapshot-тесты для UI-компонента [НАЗВАНИЕ] на [React Testing Library / Vitest / Jest / Vue Test Utils]. Что тестируем: 1) Рендер с дефолтными props. 2) Рендер с кастомными props (3–5 значимых комбинаций). 3) Состояния (loading / empty / error / filled). 4) Интерактив — клики, ввод, выбор; снимок до и после. 5) Edge cases — длинные строки, пустые массивы, NULL значения. Что НЕ тестируем (плохие практики snapshot): - Время / даты — мокать. - Случайные ID — стабилизировать через мок генератора. - Анимации в процессе — снимок только финального state. Принципы: - Имена snapshot — описательные, чтобы из diff в PR было понятно, что сломалось. - Snapshot-файлы коммитить в Git. - При изменении UI — обновлять snapshot целенаправленно, а не «жму -u пока не пройдёт». Компонент: ``` [ВСТАВЬ_КОМПОНЕНТ] ```
Snapshot-тесты — двусторонний меч. Они ловят случайные регрессии (хорошо) и заставляют обновлять snapshots на каждое мелкое изменение (плохо). Принцип «не жму -u пока не пройдёт» критичен: каждое обновление snapshot должно быть осознанным, иначе тесты теряют смысл — они начинают «подтверждать любое изменение».
🎭 Моки и стабы для внешних сервисов
Сделай моки для внешних зависимостей в тестах: [СПИСОК — БД / HTTP-клиент / очередь / файловая система / сторонний API]. Стек: [язык + framework]. Стиль моков: [строгие, проверяют вызовы / мягкие, возвращают значения]. Для каждой зависимости: 1) Базовый мок — happy path возвращает ожидаемые значения. 2) Мок с ошибкой — выбрасывает то же исключение, что и реальная зависимость. 3) Мок с задержкой — для тестов таймаутов. 4) Spy — отслеживает количество и аргументы вызовов. Принципы хорошего мока: - Воспроизводит контракт реальной зависимости (не «как удобно тесту»). - Простой в использовании из теста — не больше 2-3 строк настройки. - Не утечёт между тестами (cleanup в teardown). Антипаттерны (запрещены): - Замоканная функция возвращает невозможные значения (например, успех HTTP с пустым телом, чего реальный API никогда не сделает). - Спрятанная глобальная мутация — мок патчит модуль, а другой тест об этом не знает. - Один большой мок-фабрик на 500 строк вместо специфичных моков под каждый тест.
Главная ошибка моков — тестировать «что мок вернул то, что мы попросили». Это тавтология. Хороший мок воспроизводит реальное поведение (включая ошибки), а тест проверяет, что **наш код** правильно реагирует. Запрет на «глобальную мутацию» — против сценария, когда тесты проходят по одному, но падают при запуске вместе.
📖 README для проекта
Напиши README.md для проекта [НАЗВАНИЕ]. Контекст: Что делает проект (1 фраза): [конкретно]. Стек: [язык / фреймворк / БД]. Целевая аудитория README: [open-source / внутренний документ / клиентам]. Структура README: 1) Заголовок проекта + одна строка-обещание. 2) Бейджи (CI status, версия, лицензия) — если уместно. 3) Скриншот / GIF — если визуальный продукт. 4) Что это и зачем — 2-3 предложения, без воды. 5) Quick start — как запустить за 5 минут (установка, конфиг, первая команда). Скопировал-вставил-работает. 6) Конфигурация — переменные окружения, примеры значений. 7) Использование — основные сценарии с примерами кода. 8) Архитектура — короткая схема, ссылка на подробный ARCHITECTURE.md. 9) Разработка — как контрибьютить, как запускать тесты. 10) Лицензия и контакты. Принципы: - Quick start работает, скопированный целиком. Тестируй сам перед публикацией. - Примеры — реалистичные, не «foo / bar / baz». - Без рекламной лирики «революционный инструмент». - Картинка / GIF в начале — увеличивает звёздность в 3 раза для open-source. Описание проекта: ``` [ОПИСАНИЕ_+_СТРУКТУРА_ФАЙЛОВ] ```
Quick start, который работает at first try — главный фактор удержания читателя README. Если после copy-paste команда падает с непонятной ошибкой, человек закроет вкладку. Большинство open-source проектов теряют пользователей именно тут. Тестируйте quick start на чистой машине (или в Docker), не на своей dev-машине, где всё уже установлено.
📜 OpenAPI / Swagger документация
Напиши OpenAPI 3.0 спецификацию для endpoints ниже. Контекст: Базовый URL: [URL]. Аутентификация: [Bearer / API Key / OAuth]. Версия API: [v1 / v2]. Endpoints: [СПИСОК_ЕНДПОИНТОВ_С_МЕТОДАМИ] Для каждого endpoint: 1) Summary (короткая строка) и description (абзац). 2) Parameters — путь, query, header — с типами и required. 3) Request body — JSON Schema с примерами. 4) Responses — все возможные коды (200/201/400/401/403/404/500), для каждого schema и пример. 5) Examples — реалистичные, можно скопировать в Postman. Общие настройки: - Components/schemas — переиспользуемые модели (User, Order, Error). - Components/securitySchemes — настройка auth. - Tags — группировка по доменам. Принципы: - Реальные примеры значений, не «string» / 0 / true. - Описание каждой ошибки — что её вызвало, не просто «Bad Request». - Согласованность с реальным кодом (если код возвращает поле created_at, в схеме тоже created_at, не createdAt). Код endpoints: ``` [ВСТАВЬ_КОНТРОЛЛЕРЫ] ```
Расхождение схемы и реального кода — основной источник багов интеграции. Если в OpenAPI поле называется `userId`, а в коде — `user_id`, клиенты будут спотыкаться месяцами. Лучший подход — генерировать OpenAPI из кода (если фреймворк позволяет), иначе — линтер на согласованность.
💬 Комментарии и docstrings к сложному коду
Добавь комментарии и docstrings к коду ниже. Цель — не объяснить, ЧТО делает код (читается из имён), а **ПОЧЕМУ** он так сделан. Стиль docstring: [Google / NumPy / JSDoc / TSDoc]. Что комментировать: 1) Неочевидные алгоритмические решения (почему именно этот подход). 2) Workaround'ы (зачем такая обходка, ссылка на issue / PR / баг). 3) Ограничения и предусловия (что нельзя передавать). 4) Performance-критичные места (что не трогать без замеров). 5) Магические числа и константы — откуда взялись. Что НЕ комментировать: - Очевидное: `i++ // increment counter`. - Названия из кода: `function calculateTotal() // calculates total`. - TODO без даты и автора (через год — мусор). - Закомментированный код — удалить вообще. Docstrings (для каждой публичной функции / метода): 1) Краткое описание (1 предложение). 2) Параметры с типами и примерами. 3) Возвращаемое значение. 4) Возможные исключения. 5) Пример использования (если функция не тривиальна). Код: ``` [ВСТАВЬ_КОД] ```
Принцип «комментируй ПОЧЕМУ, а не ЧТО» — фундамент полезных комментариев. Через год после написания вы и сами не вспомните, почему здесь стоит `+ 1` (защита от off-by-one? обход бага в lib? исторически так?). Хороший комментарий отвечает именно на это. Запрет на TODO без даты и автора — потому что безымянные TODO живут годами и никто за них не отвечает.