Практическая работа №27. Тестирование «белым ящиком»

Изучите объяснения, проанализируйте исходный код и выполните задания. Главная цель — подобрать такие тестовые данные, чтобы пройти по разным ветвям программы. Ответы вводите прямо на странице. В конце сохраните работу в PDF.

1

Что такое тестирование «белым ящиком»

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

Рассмотрим программу:

age = int(input("Введите возраст: "))

if age >= 18:
    print("Доступ разрешён")
else:
    print("Доступ запрещён")

В коде есть две ветви. Если проверить только значение 20, выполнится только первая ветвь. Чтобы проверить вторую, нужно использовать значение меньше 18, например 16.

age >= 18
   |
   +---- True  ----> "Доступ разрешён"
   |
   +---- False ----> "Доступ запрещён"
Главная идея: тесты выбираются не случайно. Они подбираются на основании структуры программы.
Задание 1

Для приведённой программы подберите два теста: один должен выполнить ветвь True, второй — ветвь False. Для каждого теста укажите входное значение и ожидаемый результат.

2

Что искать в исходном коде

При тестировании «белым ящиком» особенно внимательно рассматривают конструкции, которые изменяют путь выполнения программы:

if
elif
else

for
while

return
break
continue

Пример:

def check_number(number):
    if number > 0:
        return "Положительное"
    elif number < 0:
        return "Отрицательное"
    else:
        return "Ноль"

У функции три основных результата: положительное число, отрицательное число и ноль. Значит, для проверки всех вариантов одного теста недостаточно.

Задание 2

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

3

Покрытие операторов и ветвей

Покрытие кода показывает, какая часть программы была выполнена во время тестирования.

Если тесты выполнили 7 из 10 учитываемых элементов, покрытие можно представить так:

7 / 10 × 100% = 70%

Покрытие операторов показывает, какие выполняемые операторы программы были выполнены тестами.

Покрытие ветвей требует проверить разные направления выполнения условий.

if password == "1234":
    print("Вход выполнен")
else:
    print("Неверный пароль")

Для условия выше необходимо проверить оба результата:

password == "1234" → True
password == "1234" → False
100% покрытия не означает, что программа гарантированно не содержит ошибок. Покрытие показывает, какие части структуры программы были выполнены тестами.
Задание 3

В программе есть 8 ветвей. Тестами выполнены 6. Рассчитайте покрытие ветвей в процентах. Затем объясните, что означает полученный результат.

4

Разбор функции с двумя условиями

Рассмотрим функцию расчёта стоимости доставки:

def shipping_cost(total, vip):
    if total >= 5000:
        delivery = 0
    else:
        delivery = 300

    if vip:
        delivery = max(0, delivery - 100)

    return delivery

Первое условие может дать два результата:

total >= 5000 → True
total >= 5000 → False

Второе условие тоже имеет два результата:

vip → True
vip → False

Например, тест shipping_cost(6000, False) проходит по ветви бесплатной доставки и не применяет VIP-скидку. Тест shipping_cost(3000, True) проходит по платной доставке и применяет VIP-скидку.

Задание 4

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

5

Практика: простое ветвление

Дана функция:

def check_age(age):
    if age >= 18:
        return "Совершеннолетний"
    else:
        return "Несовершеннолетний"

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

Задание 5

1. Сколько ветвей имеет функция?
2. Подберите минимальный набор тестов для выполнения каждой ветви.
3. Для каждого теста укажите ожидаемый и фактический результат после запуска программы.

6

Практика: несколько условий

Дана функция определения оценки:

def get_grade(score):
    if score < 0:
        return "Ошибка"

    if score > 100:
        return "Ошибка"

    if score >= 90:
        return "5"
    elif score >= 75:
        return "4"
    elif score >= 60:
        return "3"
    else:
        return "2"

Обратите внимание: два разных условия возвращают строку "Ошибка". Получить один раз результат «Ошибка» недостаточно — нужно проверить обе причины.

Задание 6

Подберите тестовые значения для следующих ситуаций:

СитуацияЧто нужно проверить
1score < 0
2score > 100
3Результат «5»
4Результат «4»
5Результат «3»
6Результат «2»

После запуска функции запишите ожидаемый и фактический результат каждого теста. Затем объясните, почему значений 50 и 95 недостаточно для проверки всей функции.

7

Практика: система доступа

Исходный код:

def check_access(age, has_ticket, banned):
    if banned:
        return "Доступ запрещён"

    if age < 18:
        return "Только для совершеннолетних"

    if has_ticket:
        return "Доступ разрешён"

    return "Нет билета"

Параметры:

Задание 7

Разработайте набор тестов, который позволит выполнить все четыре оператора return. Для каждого теста укажите значения трёх параметров и ожидаемый результат.

8

Практика: тестирование цикла

Дана функция:

def count_positive(numbers):
    count = 0

    for number in numbers:
        if number > 0:
            count += 1

    return count

При тестировании циклов полезно проверить разные ситуации:

Задание 8

Разработайте минимум четыре теста. Обязательно должны присутствовать: пустой список, список из одного элемента, список из нескольких элементов и список, где встречаются как положительные, так и неположительные числа.

9

Найдите непроверенные ветви

Дана функция:

def calculate_discount(price, regular_customer):
    discount = 0

    if price >= 5000:
        discount = 10

    if regular_customer:
        discount += 5

    if discount > 15:
        discount = 15

    return discount

Студент создал только два теста:

print(calculate_discount(1000, False))
print(calculate_discount(6000, False))

Нужно определить, какие результаты условий уже выполняются, а какие ещё не проверены.

Задание 9

1. Какие ветви выполняют два готовых теста?
2. Какие ветви остаются непроверенными?
3. Какие дополнительные тесты нужно добавить?
4. Составьте итоговый набор так, чтобы каждое условие хотя бы один раз получило True и хотя бы один раз False.

10

Автоматическое измерение покрытия в Python

Покрытие можно оценивать не только вручную. Для Python можно использовать пакет coverage.py.

Установка:

python -m pip install coverage

Запуск файла main.py с измерением ветвей:

coverage run --branch main.py

Текстовый отчёт:

coverage report -m

HTML-отчёт:

coverage html

После этого создаётся каталог htmlcov, внутри которого можно открыть файл index.html.

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

Выберите одну из функций из заданий 5–9, поместите её в отдельный Python-файл и запустите с измерением покрытия ветвей. Укажите, какой процент покрытия получился до добавления новых тестов и после того, как вы добавили недостающие тесты.

11

Дополнительное задание: собственная функция

Создайте собственную функцию минимум с тремя условными конструкциями. Тематика может быть любой: стоимость заказа, уровень доступа, оценка, доставка, скидка или игровая логика.

Пример структуры:

def your_function(...):
    if ...:
        ...

    if ...:
        ...
    else:
        ...

    if ...:
        ...

    return ...
Задание 11

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

12

Контрольные вопросы

  1. Чем тестирование «белым ящиком» отличается от тестирования «чёрным ящиком»?
  2. Почему при тестировании «белым ящиком» важно видеть структуру программы?
  3. Что называется покрытием кода?
  4. Что показывает покрытие операторов?
  5. Что показывает покрытие ветвей?
  6. Почему выполнения каждой строки программы может быть недостаточно для проверки всех вариантов поведения?
  7. Какие конструкции Python чаще всего создают разные пути выполнения?
  8. Какие варианты работы цикла желательно проверить?
  9. Означает ли 100% покрытия, что программа не содержит ошибок?
  10. Как понять, какого теста не хватает?
Задание 12

Кратко ответьте на контрольные вопросы. Ответы нумеруйте от 1 до 10.

Перед сдачей

✓ Указаны ФИО, группа и дата.
✓ Во всех заданиях сначала проанализирован код, затем подобраны тестовые данные.
✓ Для тестов указаны ожидаемые результаты, а где требуется — и фактические результаты запуска.
✓ Проверены разные ветви условий и разные варианты выполнения циклов.
✓ Ответы на контрольные вопросы пронумерованы.

После нажатия кнопки откроется окно печати. Выберите «Сохранить как PDF». В PDF попадут все ваши ответы полностью.

Подготовка PDF…