Когда результату проверки нельзя доверять
После изменений в коде команда смотрит на результаты тестов и автоматических проверок: если все прошло успешно, кажется, можно двигаться дальше. Но успешный статус еще не означает, что проверка действительно выполнила свою задачу. А если тест обычно проходит, но иногда падает, такие сбои легко списать на случайность.
Ринат, iOS-разработчик в Naumen, рассказал о двух таких случаях из практики и о том, почему при оценке тестов он смотрит не только на покрытие.
Для меня тесты полезны, если после изменения быстро дают понятный ответ: нужное поведение сохранилось или что-то сломалось.
Если проверка выполняется сорок минут, периодически падает без причины или требует вручную разбираться в большом логе, ей перестают доверять разработчики. Вроде бы тесты есть, но перед релизом приложение все равно приходится перепроверять руками.
Два кейса из практики
| 1. Проверка API прошла, но пропустила изменение | 2. Интеграционный тест то проходил, то падал |
|---|---|
|
В одном из наших SDK мы отдельно контролируем публичный интерфейс библиотеки. Проверка собирает актуальный артефакт, извлекает .swiftinterface и сравнивает его с сохраненной версией. Если публичный API изменился, разницу сразу видно в diff. Однажды скрипт сравнил эталон с закэшированным фреймворком, который тоже был собран до правки. В итоге изменение осталось незамеченным, хотя проверка завершилась без ошибок. После этого мы убрали автоматическое решение о том, можно ли использовать кэш. Проверка стала немного медленнее, зато снова начала отвечать на тот вопрос, ради которого существовала. |
Похожая история была с интеграционными тестами. Два параллельных запроса иногда забирали один и тот же одноразовый mock-ответ. Из-за этого тест обычно проходил, но время от времени падал. Исправление заняло несколько строк синхронизации, но эффект оказался заметным: мы перестали относиться к случайному падению как к обычному шуму. |
Что для меня важнее покрытия
В обоих случаях проблема была не в количестве тестов. Одна проверка работала с неактуальной сборкой, другая давала нестабильный результат.
Поэтому я смотрю на три вещи:
- насколько быстро проверка сообщает об ошибке;
- понятно ли, что именно сломалось;
- можно ли доверять успешному результату.
Хорошая проверка не обязана охватывать всю систему. Чтобы проверить переходы между состояниями, достаточно юнит-теста. Для сетевой политики подойдет таблица ошибок и повторов, для публичного API — сравнение интерфейса.
Чем точнее тест проверяет то, что может сломаться при конкретном изменении, тем меньше времени уходит на разбор результата.