Покрытие кода: что показывает и чего НЕ показывает

Любимая метрика менеджеров, которую легко понять неправильно.

Покрытие кода (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% не стоит.
Проверьте себя
1. Что измеряет покрытие кода (coverage)?
AПравильность работы программы
BДолю кода, который выполнился во время тестов
CСкорость тестов
DЧисло багов в коде
2. Почему 100% покрытия не гарантирует отсутствия багов?
AПотому что 100% недостижимо
BСтрока может выполниться, но её результат никто не проверил через assert
CПокрытие всегда врёт
DПотому что тесты медленные
3. Как правильно относиться к метрике покрытия?
AЛюбой ценой добиваться 100%
BНизкое покрытие — тревога; высокое — не гарантия; важны осмысленные проверки
CИгнорировать её полностью
DСчитать 50% идеалом
Поддержать проект