gadget59.ru лекции
Тестирование ПО · Лекция 4 · 24 слайда

Покрытие кода и метрики тестирования: MC/DC и не только

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

На прошлом занятии мы научились писать модульные тесты. Но как понять, что тестов достаточно? Может быть, мы проверили только 10% кода, а остальные 90% остались «в тени»?

Сегодня мы разберём покрытие кода (code coverage) — метрику, которая показывает, какая часть программы была выполнена во время тестирования. А также познакомимся с методом MC/DC, который используется в критически важных системах (авиация, медицина).

📊 Покрытие кода 🔀 Покрытие по ветвям 🧠 MC/DC 📈 Метрики
Это четвёртая лекция из цикла. Она посвящена оценке качества тестов. Без этого навыка невозможно понять, хорошо ли вы протестировали программу.
Формат: лекция + практика в конце. В следующей лекции — отладка и инструменты разработчика.

План лекции

Сегодня мы разберём, как измерять качество тестов и что такое «хорошее покрытие».

  • 1 Проблема: «тесты есть, а толку нет»
  • 2 Что такое покрытие кода
  • 3 Покрытие по строкам (statement coverage)
  • 4 Покрытие по ветвям (branch coverage)
  • 5 Покрытие по условиям (condition coverage)
  • 6 Покрытие MC/DC — «золотой стандарт»
  • 7 Пример: как достичь 100% MC/DC
  • 8 Анализ непокрытого кода
  • 9 Метрики качества тестов
  • 10 Типичные ошибки
  • 11 Итоги и практика
Если вы пропустили предыдущие лекции — вернитесь. Без понимания тест-дизайна и модульного тестирования эта тема будет непонятна.

Проблема: «тесты есть, а толку нет»

Представьте, что вы написали 100 тестов. Все они проходят успешно. Вы уверены, что программа работает правильно?

Аналогия. Представьте, что вы проверяете дом. Вы обошли все комнаты, но забыли заглянуть в подвал. Тестов много, но одна важная часть осталась непроверенной. Именно для этого нужно покрытие кода.
Покрытие кода показывает, какая часть программы была выполнена во время тестирования. Если покрытие низкое — значит, большая часть кода осталась непроверенной.
// Пример: тест есть, но он не покрывает весь код def check_age(age): if age >= 18: return "Взрослый" else: return "Ребёнок" # Если мы протестировали только check_age(25), # то ветка "else" осталась непроверенной. Покрытие — 50%.

Что такое покрытие кода

Покрытие кода (code coverage) — это процент программного кода, который был выполнен во время тестирования.

Если покрытие 80% — значит, 80% строк (или ветвей, или условий) были проверены тестами. Остальные 20% — не проверены.
📈
Высокое покрытие
Большая часть кода проверена. Меньше шансов на скрытые ошибки.
📉
Низкое покрытие
Много «слепых зон». Ошибки могут прятаться в непроверенном коде.
100% покрытие не гарантирует отсутствие ошибок. Но низкое покрытие гарантирует, что часть кода не проверена вообще.

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

Покрытие по строкам (statement coverage) — простейший вид покрытия. Считает, сколько строк кода было выполнено.

// Пример def foo(x): if x > 0: print("Положительное") // строка 1 else: print("Не положительное") // строка 2 return x // строка 3
ТестКакие строки выполненыПокрытие foo(5)1, 32 из 3 (67%) foo(5) и foo(-1)1, 2, 33 из 3 (100%)
Покрытие по строкам — это «минимум». Но оно не гарантирует, что проверены все ветви условий.

Покрытие по ветвям

Покрытие по ветвям (branch coverage) — более строгий вид. Считает, сколько ветвей условных операторов было выполнено.

// Пример if (x > 0) { // ветвь 1 (true) } else { // ветвь 2 (false) }
ТестКакие ветви выполненыПокрытие x = 5только true50% x = 5, x = -1true и false100%
Покрытие по ветвям строже, чем по строкам. Если условие имеет пустую ветвь else — её тоже нужно проверить.
100% покрытие по строкам не гарантирует 100% покрытия по ветвям. Обратное тоже верно. Это разные метрики.

Покрытие по условиям

Покрытие по условиям (condition coverage) — ещё более строгий вид. Считает, что каждая компонента логического выражения приняла все возможные значения (true и false).

// Пример: условие с двумя компонентами if (a > 0 && b > 0) { // тело }
Тестa > 0b > 0Покрытие a = 5, b = 5truetrue50% (только true) a = -1, b = -1falsefalse100% (true и false)
Покрытие по условиям требует, чтобы каждая компонента хотя бы раз была true и хотя бы раз false. Но оно не гарантирует, что проверена вся логика выражения.

Покрытие MC/DC — «золотой стандарт»

MC/DC (Modified Condition/Decision Coverage) — это самый строгий вид покрытия. Он используется в критически важных системах: авиации, медицине, космосе.

MC/DC требует, чтобы каждая компонента условия независимо влияла на результат всего условия. То есть, если мы меняем только одну компоненту, результат должен меняться.
ТребованиеЧто значит Каждое условиепринимает true и false Каждая компонентапринимает true и false Независимое влияниеизменение одной компоненты меняет результат
MC/DC — это стандарт для авиационного ПО (DO-178B/C). Если программа прошла MC/DC — она проверена максимально тщательно.

Пример: как достичь 100% MC/DC

Рассмотрим условие if (A || B). Построим тесты для MC/DC.

ТестABA || BЧто проверяем 1000базовый случай 2101влияние A 3011влияние B
Трёх тестов достаточно: мы показали, что и A, и B независимо влияют на результат. Это и есть MC/DC для OR.
// Для условия if (A && B) тесты будут другими // 1. A=1, B=1 (базовый) // 2. A=0, B=1 (влияние A) // 3. A=1, B=0 (влияние B)

Сравнение видов покрытия

Соберём все виды покрытия в одну таблицу.

Вид покрытияЧто считаетСтрогость По строкамвыполненные строкинизкая По ветвямвыполненные ветвисредняя По условиямзначения компонентвысокая MC/DCнезависимое влияниемаксимальная
Чем строже покрытие, тем больше тестов нужно. Но и уверенность в качестве программы выше.
100% покрытие по строкам — это минимум, который должен быть в любом проекте. Для критически важных систем — только MC/DC.

Анализ непокрытого кода

Покрытие — это не только цифра. Важно понимать, какой код остался непокрытым и почему.

ПричинаЧто делать Недостаточно тестовдобавить тесты «Мёртвый» кодудалить его Защитный коддокументировать, почему не покрыт Недостижимый кодудалить или исправить
«Мёртвый код» (dead code) — это код, который никогда не выполняется. Он засоряет программу и усложняет её понимание. Если покрытие показывает, что какой-то код не выполняется — возможно, его пора удалить.
Анализ покрытия — это не «погоня за 100%». Это способ найти слепые зоны и понять, почему они возникли.

Метрики качества тестов

Покрытие — не единственная метрика. Есть и другие показатели, которые помогают оценить качество тестов.

МетрикаЧто показывает Покрытие кода% выполненных строк/ветвей Количество тестовсколько всего тестов Процент прошедшихсколько тестов проходит Время выполнениякак быстро работают тесты Мутационное покрытиенасколько тесты «ловят» ошибки
Мутационное тестирование (mutation testing) — это когда в код специально вносят ошибку (мутацию) и смотрят, обнаружат ли её тесты. Если тесты не замечают мутацию — они слабые.

Типичные ошибки новичков

1. Гнаться за 100% любой ценой
Писать бессмысленные тесты, которые проверяют очевидное. Лучше 80% осмысленных, чем 100% бесполезных.
2. Игнорировать покрытие
«У меня есть тесты, значит всё хорошо». Без покрытия вы не знаете, что именно проверено.
3. Считать, что 100% покрытие = 0 ошибок
Покрытие не гарантирует отсутствие ошибок. Оно лишь показывает, что код был выполнен.
4. Не анализировать непокрытый код
Важно понять, почему код не покрыт. Может, это «мёртвый» код, а может — важная функция.
5. Путать виды покрытия
Покрытие по строкам и по ветвям — это разные метрики. Нельзя сказать «у меня 100%», не уточнив, какое именно покрытие.

Практическое задание

Примените полученные знания на практике.

Задание 1

Для функции check_age(age) (см. слайд 3) составьте тесты так, чтобы покрытие по строкам было 100%.

Задание 2

Для условия if (a > 0 && b > 0) постройте тесты для покрытия по условиям и для MC/DC.

Задание 3

Объясните своими словами, чем покрытие по ветвям отличается от покрытия по условиям.

Решения разберём на практическом занятии. Помните: цель не «угадать правильный ответ», а научиться системно думать о покрытии.

Шпаргалка

Сохраните этот слайд — здесь все основные понятия лекции.

ТерминЧто значит Покрытие кода% выполненного кода По строкамсколько строк выполнено По ветвямсколько ветвей выполнено По условиямзначения компонент условий MC/DCнезависимое влияние компонент Мёртвый кодкод, который никогда не выполняется Мутационное тестированиепроверка тестов через внесение ошибок

Итоги лекции

Подведём итоги. Вот что вы теперь знаете.

  • ✅ Покрытие кода — это процент кода, выполненного во время тестирования.
  • ✅ Покрытие по строкам — самый простой вид. Не гарантирует проверку всех ветвей.
  • ✅ Покрытие по ветвям — строже. Требует проверки всех ветвей условий.
  • ✅ Покрытие по условиям — ещё строже. Требует проверки всех компонент логических выражений.
  • ✅ MC/DC — «золотой стандарт». Требует независимого влияния каждой компоненты.
  • ✅ Анализ непокрытого кода помогает найти «мёртвый» код и пробелы в тестах.
  • ✅ 100% покрытие не гарантирует отсутствие ошибок. Но низкое покрытие — это сигнал тревоги.
В следующей лекции мы перейдём к отладке — искусству находить и исправлять ошибки в коде. Это следующий шаг после тестирования.

Домашнее задание

Задания для самостоятельной работы. Первые два обязательны, остальные — для оценки «отлично».

  1. Для функции check_age(age) постройте тесты для 100% покрытия по ветвям.
  2. Для условия if (a > 0 || b > 0) постройте тесты для MC/DC.
  3. Объясните своими словами, почему 100% покрытие по строкам не гарантирует 100% покрытия по ветвям.
  4. Найдите в интернете пример «мёртвого кода» и объясните, почему он появляется.
  5. Попробуйте измерить покрытие своего проекта (если есть) с помощью инструментов (pytest-cov для Python).
Если задание кажется сложным — разбейте его на части. Сначала тесты для одного условия, потом для другого.

Что дальше?

В этом блоке по тестированию у нас ещё несколько материалов.

  • Лекция 5: отладка и инструменты разработчика.
  • Практика 3: интеграционное тестирование.
  • Практика 4: покрытие кода на Python (pytest-cov).
Покрытие кода — это инструмент, который помогает понять, насколько хорошо вы протестировали программу. Но это не самоцель. Главное — найти и исправить ошибки.

Спасибо за внимание!

📊

Покрытие — это компас, а не цель

Он показывает, куда двигаться. Но решение о том, что и как тестировать, всегда остаётся за вами.

📈 Покрытие 🔀 Ветви 🧠 MC/DC 🚀 практика