← Назад к вопросам

Что покрываешь тестами в белом ящике

2.0 Middle🔥 231 комментариев
#Теория тестирования

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Тестовое покрытие при тестировании «белого ящика»

При тестировании методом «белого ящика» (white-box testing) я, как инженер, имею доступ к исходному коду и внутренней структуре приложения. Моя цель — проверить корректность внутренней логики, потоков данных и выполнение всех ветвлений кода. Покрытие в этом контексте — это метрика, показывающая, какая часть кода была «затронута» тестами. Ключевые типы покрытия, которые я анализирую и стремлюсь обеспечить:

1. Покрытие операторов (Statement Coverage)

Это минимальный базовый уровень. Цель — выполнить каждую исполняемую строку кода хотя бы один раз.

  • Что проверяем: Доходит ли исполнение до каждой строки.
  • Недостаток: Не гарантирует проверку всех условий. Код с условными операторами может быть пройден, но логические ошибки в условиях останутся.
// Пример: Для 100% statement coverage достаточно одного теста с a > b
public int max(int a, int b) {
    int result; // Declare
    if (a > b) {
        result = a; // Нужно выполнить эту строку
    } else {
        result = b; // И эту строку
    }
    return result;
}
// Тест 1: a=5, b=3 -> проходит обе ветки (if и else? Нет, только if).
// Тест 2: a=3, b=5 -> необходим для покрытия ветки 'else'.

2. Покрытие ветвей (Branch Coverage / Decision Coverage)

Более строгий уровень. Цель — выполнить каждую возможную ветвь условных операторов (if, else, case, циклы) хотя бы один раз. Это означает прохождение всех путей «истина» и «ложь» для каждого условия.

  • Что проверяем: Все ли варианты решений в коде были приняты.
  • Преимущество: Обнаруживает ошибки, связанные с недостижимым или неверным ветвлением.
# Для 100% branch coverage нужно два теста
def check_access(age, is_admin):
    if age >= 18 or is_admin: # Два условия: age >= 18 (True/False), is_admin (True/False)
        return "Access granted"
    else:
        return "Access denied"
# Тест 1: age=20, is_admin=False -> условие True (через age)
# Тест 2: age=16, is_admin=True -> условие True (через is_admin)
# Тест 3: age=16, is_admin=False -> условие False (ветка 'else')

3. Покрытие условий (Condition Coverage)

Фокусируется на каждом атомарном логическом условии внутри составного выражения. Каждое условие должно быть равно и true, и false.

  • Что проверяем: Все ли элементарные условия были протестированы в обоих состояниях.
  • Важно: 100% condition coverage не гарантирует 100% branch coverage.
// Условие (age >= 18) и (isVIP) должны быть протестированы и как true, и как false.
function canEnterClub(age, isVIP) {
    return age >= 18 && isVIP;
}
// Для condition coverage:
// Тест 1: age=20 (true), isVIP=true (true) -> весь результат true
// Тест 2: age=16 (false), isVIP=false (false) -> весь результат false
// Но branch coverage здесь будет достигнута этими же тестами.

4. Комбинаторное покрытие условий (Modified Condition/Decision Coverage - MC/DC)

Критически важный стандарт для высоконадежных систем (авионика, медицина). Требует, чтобы каждое условие независимо влияло на итоговое решение.

  • Что проверяем: Можно ли показать, что изменение одного условия при фиксированных остальных меняет результат всего выражения.

5. Покрытие путей (Path Coverage)

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

  • Что проверяем: Все ли последовательности операторов и ветвлений были выполнены.
  • Сложность: Количество путей растет экспоненциально с увеличением условных операторов и циклов.

6. Покрытие функций/методов (Function Coverage)

Базовый организационный уровень. Цель — вызвать каждую функцию или метод системы хотя бы один раз.

  • Что проверяем: Нет ли «мертвого», неиспользуемого кода.

На практике я не стремлюсь к 100% по всем метрикам везде — это экономически нецелесообразно. Моя стратегия:

  1. Определение критичности: Модули с бизнес-логикой, алгоритмами, расчетами, безопасностью требуют высокого покрытия ветвей и условий (желательно MC/DC).
  2. Использование инструментов: Я применяю анализаторы покрытия (JaCoCo для Java, Istanbul для JS, Coverage.py для Python), которые интегрируются в CI/CD и генерируют отчеты.
  3. Анализ и приоритизация: Отчет показывает непокрытые строки или ветви. Я анализирую их критичность: это обработка ошибок, крайние случаи или важная бизнес-логика? Исходя из этого пишу тесты.
  4. Фокус на качестве тестов: Высокий процент покрытия — не самоцель. Важны качественные, содержательные тесты, которые проверяют корректность, а не просто «проезжают» по коду. Плохой тест с высоким покрытием дает ложное чувство безопасности.

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