Back

Что на самом деле показывает покрытие кода

Что на самом деле показывает покрытие кода

Ваш набор тестов проходит успешно. Отчёт о покрытии показывает 85%. Дашборд зелёный. Но действительно ли эта цифра означает, что ваш код работает корректно?

Покрытие кода — одна из самых заметных метрик во фронтенд-тестировании, но её часто неправильно понимают. В этой статье объясняется, что на самом деле измеряют метрики покрытия, почему высокие проценты могут скрывать серьёзные пробелы и как интерпретировать эти цифры в реальных JavaScript-проектах.

Ключевые выводы

  • Покрытие кода измеряет, какие строки выполнились во время тестов, а не то, ведёт ли себя код правильно
  • Покрытие ветвлений выявляет пробелы, которые упускает покрытие строк, особенно в условной логике
  • Высокие проценты покрытия могут создавать ложную уверенность, когда в тестах отсутствуют значимые проверки
  • Разные провайдеры покрытия (Istanbul vs V8) могут выдавать разные цифры для идентичного кода
  • Используйте покрытие как диагностический инструмент для поиска слепых зон, а не как показатель качества

Что на самом деле измеряет покрытие кода

Покрытие кода говорит вам об одном: какие части вашего исходного кода выполнились во время запуска тестов. Вот и всё.

Оно не говорит, правильно ли вёл себя код. Оно не подтверждает, что ваши проверки поймали баги. Оно не верифицирует, что граничные случаи были обработаны. Инструменты покрытия просто инструментируют ваш код и отслеживают, что выполнилось.

Когда вы запускаете jest --coverage или включаете покрытие в Vitest, инструмент отслеживает выполнение и возвращает проценты. Эти проценты представляют выполнение, а не корректность.

Понимание метрик покрытия тестами

Большинство инструментов покрытия для JavaScript отображают несколько различных метрик. Каждая измеряет что-то своё.

Покрытие строк (line coverage) отслеживает, выполнилась ли каждая строка исходного кода. Покрытие инструкций (statement coverage) подсчитывает выполненные инструкции — что отличается от строк, когда несколько инструкций находятся на одной строке. Покрытие функций (function coverage) показывает, была ли каждая функция вызвана хотя бы один раз.

Покрытие ветвлений (branch coverage) идёт глубже. Оно отслеживает, выполнился ли каждый путь через условную логику. Блок if/else имеет две ветви. Покрытие ветвлений требует выполнения обоих путей.

Вот где это различие имеет значение:

function getDiscount(user) {
  if (user.isPremium || user.hasPromo) {
    return 0.2
  }
  return 0
}

Тест с user.isPremium = true достигает 100% покрытия строк. Каждая строка выполняется. Но покрытие ветвлений выявляет пробел: вы никогда не тестировали случай, когда isPremium равен false, но hasPromo равен true, или когда оба равны false.

Вот почему важно различие между покрытием ветвлений и покрытием строк. Покрытие строк может достичь 100%, оставляя логические пути полностью непротестированными.

Почему высокое покрытие может вводить в заблуждение

Тест, который выполняет код без значимых проверок, завышает покрытие, не отлавливая баги. Рассмотрим:

test('processes order', () => {
  processOrder(mockOrder)
  // Нет проверок
})

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

Инструменты покрытия не могут различить тест, который тщательно проверяет поведение, и тест, который просто запускает код. Оба одинаково засчитываются в ваш процент.

Провайдеры покрытия: почему цифры меняются

Современное покрытие кода в JavaScript опирается на различные подходы к инструментации. Jest по умолчанию использует инструментацию в стиле Istanbul, которая трансформирует ваш код перед выполнением. Vitest поддерживает как Istanbul, так и нативное покрытие на основе V8.

Эти провайдеры могут выдавать разные цифры для идентичного кода и тестов. Покрытие V8 работает на уровне движка и иногда считает покрытие иначе, чем подход Istanbul с трансформацией исходного кода.

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

Относитесь к цифрам покрытия как к направляющим сигналам, а не точным измерениям.

Где покрытие помогает, а где вводит в заблуждение

Покрытие полезно для:

  • Выявления полностью непротестированных файлов или функций
  • Обнаружения мёртвого кода, который никогда не выполняется
  • Нахождения ветвей, которые вы забыли протестировать
  • Отслеживания трендов с течением времени (падение покрытия на новом коде)

Покрытие вводит в заблуждение, когда:

  • Команды гонятся за процентами вместо тестирования поведения
  • Тесты выполняют код без проверки результатов
  • Высокие цифры создают ложную уверенность в качестве тестов
  • Пороговые значения давят на разработчиков, заставляя писать поверхностные тесты

Интерпретация покрытия в реальных проектах

Используйте отчёты о покрытии как диагностический инструмент, а не как показатель качества. Когда вы видите непокрытые строки, спросите: имеет ли значение этот путь кода? Если он обрабатывает ошибки, граничные случаи или критическую логику, напишите для него тесты. Если он действительно недостижим или тривиален, подумайте, должен ли этот код вообще существовать.

Просматривайте покрытие вместе с вашими тестами, а не вместо них. Файл с 60% покрытия и сильными проверками часто даёт больше уверенности, чем файл с 95% покрытия и слабыми тестами.

В код-ревью различия в покрытии помогают определить, включает ли новый код тесты. Но само ревью должно оценивать, проверяют ли эти тесты значимое поведение.

Как заставить покрытие работать для вашей команды

Устанавливайте пороговые значения покрытия обдуманно. Минимум в 70-80% предотвращает очевидные пробелы, не подталкивая команды к «театру покрытия». Что ещё важнее, сосредоточьтесь на покрытии ветвлений для кода с большим количеством логики — оно отлавливает пробелы, которые упускает покрытие строк.

Запускайте покрытие в CI для отслеживания трендов, но не проваливайте сборки из-за небольших падений. Рефакторинг часто временно снижает покрытие, когда протестированный код удаляется или реструктурируется.

Заключение

Цель — не цифра. Цель — уверенность в том, что ваши тесты отлавливают реальные баги до того, как их увидят пользователи. Покрытие помогает вам найти слепые зоны. Хороший дизайн тестов, значимые проверки и вдумчивые ревью определяют, действительно ли вы их заполняете.

Часто задаваемые вопросы

Большинство команд ориентируются на 70-80% как разумный минимум. Однако процент имеет меньшее значение, чем то, что вы тестируете. Сосредоточьтесь на покрытии критических путей, обработки ошибок и бизнес-логики. Более низкий процент с сильными проверками часто лучше высокого покрытия с поверхностными тестами, в которых отсутствует значимая верификация.

Избегайте провала сборок из-за небольших падений покрытия. Рефакторинг часто временно снижает покрытие, когда протестированный код удаляется или реструктурируется. Вместо этого используйте тренды покрытия для выявления паттернов и просматривайте различия в покрытии в пулл-реквестах, чтобы убедиться, что новый код включает соответствующие тесты.

Разные провайдеры покрытия используют различные подходы к инструментации. Istanbul трансформирует код перед выполнением, в то время как V8 работает на уровне движка. Эти подходы измеряют немного разные вещи, поэтому смена провайдеров или обновление инструментов может сдвинуть отображаемые цифры без каких-либо фактических изменений кода.

Проверяйте ваши проверки (assertions), а не только цифры покрытия. Тесты без проверок или с тривиальными проверками завышают покрытие, не отлавливая баги. Инструменты мутационного тестирования могут помочь, внося небольшие изменения в код, чтобы проверить, что ваши тесты действительно проваливаются, когда поведение неожиданно меняется.

Gain control over your UX

See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay