Зелёный тест не доказывает, что код правильный. Он доказывает, что ошибку пока не нашли. Эту мысль точно сформулировал Эдсгер Дейкстра ещё в 1970 году: «Тестирование программы может показать наличие ошибок, но никогда не докажет их отсутствие». С тех пор ничего не изменилось, изменилась только цена вопроса.
Проваленный тест — это информация. Он показывает конкретное место, где что-то сломалось. Прошедший тест информации почти не даёт: он говорит лишь о том, что конкретный вход, на конкретном пути, в этот раз не упал. Между этим скромным фактом и «код работает» лежит пропасть, в которой живут продакшн-баги.
Зелёный — это отсутствие пойманной ошибки, а не присутствие правильности.
Самый опасный вид теста — тот, который проверяет ровно то, что и так работает. Он не врёт, но создаёт ощущение защищённости. А ощущение защищённости — худший враг ревью.
Почему сейчас это стало острее
ИИ-инструменты за секунды выдают функцию и набор тестов, которые вместе проходят. И вместе же могут быть неправильными: код обрабатывает те случаи, которые проверяют тесты, а тесты проверяют те случаи, которые умеет обрабатывать код. Ни тот, ни другой не касаются краевого случая, который развалится у пользователя. Всё выглядит готовым — и совершенно пустым.
Проблема не в том, что ИИ генерирует плохой код. Проблема в том, что он оптимизируется под зелёную галочку, а не под реальный мир. Код и тест могут идеально согласовываться друг с другом и при этом оба быть далеки от задачи, которую вы на самом деле решали.
Это делает привычку Дейкстры не просто хорошим тоном, а ключевым навыком инженера. Когда и код, и тесты стоят дёшево, единственное, что нельзя сгенерировать — желание искать, где ещё сломано. Это научная привычка: не пытаться подтвердить свою идею, а пытаться её опровергнуть. И доверять коду чуть больше только после того, как он пережил честную попытку быть сломанным.
Не пытайтесь подтвердить код. Пытайтесь его сломать.
Как тестировать со смыслом
Разница между тестом-подтверждением и тестом-попыткой сломать видна на уровне вопросов.
| Подход | Вопрос | Что даёт зелёный результат |
|---|---|---|
| Подтверждающий тест | Работает ли на этом примере? | Этот пример не упал. И всё. |
| Пытающийся сломать | Какое условие должно развалить код и почему оно этого не сделало? | Код пережил попытку его развалить. Границы стали чуть понятнее. |
Первая строчка — привычный режим. Вторая — то, что реально защищает от багов. Несколько конкретных привычек.
- Для каждой функции спрашивайте: какой вход её сломает? Пишите этот тест первым. Если не можете придумать ни одного — вы ещё не поняли функцию.
- Тестируйте края, а не середину: пустой вход, максимум, off-by-one, параллельный доступ, путь ошибки, который никто не запускает.
- Сформулируйте инвариант, который код обязан соблюдать, и напишите тест, единственная задача которого — этот инвариант нарушить.
- Когда ИИ отдаёт вам код с зелёными тестами, считайте это началом ревью, а не его концом. Добавьте тот случай, который модель не догадалась проверить.
- Если баг дошёл до продакшена — сначала напишите тест, который его ловит, и только потом исправление. Этот тест ценнее самого фикса.
Всё это не значит, что тесты не нужны. Нужны. Они один из лучших инструментов в разработке. Но тестовый набор — это запись тех отказов, которые вы пошли искать, и он не шире вашего представления о том, что может пойти не так. Расширяете представление — тесты становятся сильнее. Пропускаете — зелёная галочка превращается в ложное спокойствие, пока баг не найдёт пользователь.
Смотрите внимательнее всего на тот код, в котором уверены больше всего. И относитесь к зелёному тесту как к вопросу, а не ответу.
Комментарии (0)
Войдите, чтобы комментировать.
Пока нет комментариев. Будьте первым.