Покрытие кода: что показывает и чего НЕ показывает
Любимая метрика менеджеров, которую легко понять неправильно.
Покрытие кода (code coverage) — это доля строк (или ветвей) кода, которые выполнились хотя бы раз во время прогона тестов. Оно показывает, что код исполнялся, но не что он проверен.
Что измеряет покрытие
Инструмент покрытия запускает тесты и отмечает, какие строки выполнились. Если из 100 строк выполнилось 80 — покрытие 80%. Виды: построчное (line), по ветвям (branch — учитывает оба исхода if), по функциям. Branch-покрытие строже и полезнее.
Главная ловушка: исполнено ≠ проверено
Строка может выполниться во время теста, но её результат никто не проверил. Покрытие засчитает её, а баг останется. Рассмотрим тест без единого assert на результат функции:
def calc_total(items):
# БАГ: должно быть sum, но стоит max
return max(items)
# «Тест», который выполняет функцию, но НЕ проверяет результат
def bad_test():
calc_total([10, 20, 30]) # строка выполнилась -> 100% покрытие
# ...но мы ничего не проверили!
bad_test()
print("Покрытие 100%, но баг (max вместо sum) НЕ пойман — нет assert на результат")
# А вот настоящий тест ловит баг:
try:
assert calc_total([10, 20, 30]) == 60
print("ok")
except AssertionError:
print(f"Настоящий тест поймал баг: получили {calc_total([10, 20, 30])}, ждали 60")
Вывод:
Покрытие 100%, но баг (max вместо sum) НЕ пойман — нет assert на результат Настоящий тест поймал баг: получили 30, ждали 60
Вот суть проблемы: 100% покрытия достигнуто, но качество теста нулевое, потому что нет проверки результата. Покрытие говорит «код запускался», а не «код работает правильно».
Как пользоваться метрикой здраво
- Низкое покрытие — тревога. Если 30% кода вообще не выполняется тестами, там точно есть непроверенные места.
- Высокое покрытие — не гарантия. 90% с хорошими assert — отлично; 90% без проверок — самообман.
- Не гонитесь за 100%. Последние проценты часто покрывают тривиальный или защитный код; усилия не окупаются.
Покрытие хорошо отвечает на вопрос «что мы забыли протестировать вообще», но не на вопрос «хорошо ли мы протестировали».
Итог
- Покрытие показывает, какой код выполнился, а не правильно ли он работает.
- 100% покрытия без осмысленных assert не значит «нет багов».
- Низкое покрытие — сигнал тревоги; гнаться за 100% не стоит.