Выполненная строка — ещё не проверенное поведение

Представим функцию, которая рассчитывает скидку. Тест вызывает её для покупателя со скидкой 10%, и программа проходит через каждую строку функции. Но если тест лишь проверяет, что функция не завершилась с ошибкой, он не заметит, что вместо скидки к цене прибавили 10%. Код исполнился, а результат остался непроверенным.

Покрытие показывает, какие участки программы запускались во время тестов, а не сравнивает их результат с тем, который нужен пользователю. Для такой проверки тесту нужно содержать утверждение: например, что цена после скидки равна ожидаемой. Если ожидаемое значение задано неверно или проверка слишком расплывчата, процент покрытия этого тоже не выявит.

Какие проверки могут скрыться за одним процентом

Строка иногда выполняется только при одном из нескольких возможных условий. Например, код выбирает один путь для положительной суммы и другой — для нулевой. Тест может пройти по первому пути, оставив второй непроверенным, хотя строка с условием уже будет считаться выполненной. Поэтому отдельно измеряют покрытие ветвей — долю проверенных вариантов перехода в таких развилках.

Но и полное покрытие ветвей не означает, что проверены все сочетания входных данных или верно сформулированы ожидания. Оно уточняет картину, но не превращает тесты в доказательство правильности программы.

На что покрытие полезно

Этот показатель помогает найти код, который тесты вообще не затрагивают: например, обработчик ошибки, о котором забыли. Высокое покрытие может говорить о широком охвате программы тестами, но качество зависит от того, что именно тесты утверждают и какие случаи они проверяют. Две программы с одинаковым процентом покрытия могут иметь совершенно разную надёжность — одна проверяет результаты, а другая лишь проводит тесты по коду.