Автоматические проверки кода — линтеры, тесты, CI-пайплайны — призваны ловить ошибки до того, как они попадут в продакшн. Но если настроить их неправильно, они превращаются в формальность: зелёный статус успокаивает, а проблема остаётся. В этой статье — пять реальных историй из практики разработки с ИИ-агентом, где проверки были зелёными, но ничего не проверяли. Мы разберём, почему так происходит, и дадим конкретные шаги, чтобы ваши проверки работали.
История 1: Тест, который проверял только отсутствие ошибок
Одна из первых проверок в проекте должна была убедиться, что функция возвращает корректный результат. Написали тест: вызываем функцию, проверяем, что не выбрасывается исключение. Тест зелёный. Но функция возвращала undefined вместо ожидаемого объекта. Ошибка не ловилась, потому что тест не проверял возвращаемое значение. Урок: тест без утверждений (assert) — это не тест, а имитация. Всегда проверяйте конкретный ожидаемый результат, а не просто отсутствие падения.
История 2: Линтер, который игнорировал правила
Настроили ESLint с набором правил, но в конфиге случайно оставили extends: [] и не подключили рекомендуемые наборы. Линтер запускался, не находил ошибок и показывал зелёный. Разработчики расслабились, а в коде копились проблемы. Обнаружилось это случайно, когда новый разработчик попробовал запустить линтер с другим конфигом. Урок: проверяйте, что линтер действительно применяет правила. Запустите его на заведомо плохом коде и убедитесь, что он ругается.
История 3: CI, который не собирал проект
В пайплайне CI был шаг сборки, но из-за опечатки в скрипте он завершался с кодом 0, даже если сборка падала. Зелёный статус держался месяцами. Ошибка вскрылась, когда понадобилось развернуть новую версию. Урок: CI должен не только запускаться, но и корректно сообщать о失败. Проверяйте, что каждый шаг возвращает ненулевой код при ошибке. Используйте set -e в bash-скриптах или аналогичные механизмы.
История 4: Покрытие кода как самоцель
Увидели, что покрытие тестами низкое, и добавили тесты, которые просто вызывали функции без проверок. Покрытие выросло до 90%, но количество багов не уменьшилось. Более того, появилась ложная уверенность. Урок: покрытие — метрика, но не гарантия качества. Важнее, какие сценарии проверяются. Лучше 50% покрытия с осмысленными тестами, чем 90% с пустыми.
История 5: Проверка, которая проверяла саму себя
Был тест, который сравнивал вывод функции с эталоном, но эталон генерировался той же функцией. Тест всегда проходил, даже если функция работала неправильно. Урок: не используйте проверяемую функцию для создания ожидаемого результата. Ожидаемые значения должны быть независимыми — либо захардкожены, либо получены из другого источника.
Как сделать проверки надёжными: конкретные шаги
Чтобы автоматические проверки не врали, следуйте этим рекомендациям:
- Проверяйте, что проверки работают. Внесите намеренную ошибку в код и убедитесь, что тест или линтер её ловит. Если нет — исправьте проверку.
- Используйте мутационное тестирование. Оно автоматически вносит мелкие ошибки в код и смотрит, падают ли тесты. Если тесты не реагируют — они бесполезны.
- Настройте CI на падение при любых ошибках. Убедитесь, что каждый шаг возвращает корректный код завершения. Добавьте шаг, который явно проверяет статус предыдущих шагов.
- Регулярно пересматривайте тесты. Устаревшие тесты могут проверять не то, что нужно. Удаляйте или обновляйте их.
- Не гонитесь за метриками. Покрытие и количество тестов — вторичны. Главное — какие баги они предотвращают.
Типичные ошибки, которых стоит избегать: тесты без утверждений, линтеры с пустым конфигом, CI с игнорированием кодов возврата, генерация ожидаемых значений той же функцией, фокус на покрытии вместо сценариев.
В проекте kb-engine сейчас 21 автоматическая проверка, и каждая из них была пересмотрена после описанных случаев. Это заняло время, но теперь зелёный статус действительно означает, что код соответствует ожиданиям. Помните: правило, которое можно пропустить, никто соблюдать не будет. Автоматизация должна быть строгой и проверенной.