5.5. Тестирование программы
Информатика, 7 класс. Учебник: Кадыркулов Р. А., Рыскулбекова А. Д., Нурмуханбетова Г. К. (Алматыкітап баспасы, 2023). Раздел 5: Практическое программирование. Страницы 157–161.
Чему научишься
- Объяснять, что такое тест и чем тестирование отличается от исправления ошибок.
- Знать три этапа тестирования: нормальные, граничные и исключительные условия.
- Заранее готовить тестовые данные и ожидаемые ответы.
- Проверять программу на нескольких наборах данных и находить слабые места.
Разминка
- Что понимается под тестированием программы? Это проверка: мы запускаем программу на заранее подобранных данных и смотрим, совпал ли её ответ с тем, который мы ждали.
- Какие бывают типы тестов? По условиям, в которых проверяем: обычные (нормальные) данные, крайние (граничные) значения и «неправильные» данные, которых программа не ждёт (исключительные).
Разбираемся
Чем тест отличается от «починки»
Допустим, ты написал программу, и она запустилась без красных сообщений об ошибке. Это ещё не значит, что она считает правильно. Здесь два разных дела.
- Исправление ошибок (отладка): программа не запускается или падает, потому что где-то опечатка или нарушены правила записи (синтаксические ошибки). Ты ищешь причину и чинишь.
- Тестирование: программа запускается, а мы проверяем, правильный ли ответ она даёт.
📌 Тест — это набор входных данных вместе с ответом, который программа должна выдать. Ответ мы определяем заранее, головой или на бумаге, а не списываем с экрана после запуска.
⚠️ Частая ошибка. Запустить программу, посмотреть на ответ и написать «ожидалось именно это». Так любой неверный ответ покажется правильным. Сначала посчитай в уме, потом запускай.
Три этапа проверки
Возьмём простую программу. В магазине игр при покупке от 5000 тенге даётся скидка 10 %. Программа получает сумму покупки и выводит, сколько платить.
price = int(input()) # сумма покупки, тг
if price >= 5000:
price = price - price // 10 # скидка 10 %
print(price)
1. Нормальные условия. Обычные данные, как в жизни.
2. Граничные условия. Значения на самой границе: там, где условие меняет решение, и на краях допустимых чисел. Здесь граница — число 5000. Проверяем и 4999 (скидки ещё нет), и 5000 (скидка уже есть).
3. Исключительные условия. Данные, которые программа не должна принимать: отрицательная сумма, буквы вместо числа. Хорошая программа такие данные отклоняет, а не печатает странный ответ.
| Ввод | Что ждём | Этап | Что выдала программа |
|---|---|---|---|
| 3000 | 3000 | нормальный | 3000 |
| 8000 | 7200 | нормальный | 7200 |
| 4999 | 4999 | граничный | 4999 |
| 5000 | 4500 | граничный | 4500 |
| −100 | сообщение об ошибке | исключительный | −100 (плохо) |
Последний тест нашёл слабое место: программа «приняла» отрицательную сумму. Исправляем.
price = int(input()) # сумма покупки, тг
if price < 0:
print("Ошибка: сумма не может быть отрицательной")
elif price >= 5000:
print(price - price // 10) # скидка 10 %
else:
print(price)
Теперь ввод −100 даёт сообщение об ошибке, а остальные тесты дают те же ответы.
💡 Правило тестировщика: для каждого условия
ifпридумай тест по обе стороны от границы и ровно на границе. Тогда ошибки вроде>вместо>=не спрячутся.
🌟 Крупные игры и приложения перед выходом проверяют целые команды тестировщиков. Они специально вводят странные данные, нажимают всё подряд и ищут, что сломается.
Вердикт: программа «условно правильная»
Если на всех продуманных тестах ответы совпали с ожидаемыми, программу можно считать условно правильной. «Условно» потому, что мы проверили не все на свете входные данные. Чем лучше подобраны тесты, тем меньше шансов, что ошибка проскочит.
👨👩👧 Родителю. Попросите ребёнка показать, как он проверял программу. Хороший вопрос: «А что будет, если ввести ноль или самое большое число?» Привычка проверять края пригодится и вне информатики.
Проверь себя
- Чем исправление ошибок отличается от тестирования? При исправлении мы убираем синтаксические ошибки, из-за которых программа не работает. При тестировании проверяем, правильно ли работающая программа отвечает на подготовленные данные.
- Почему ожидаемый результат нельзя брать с экрана после запуска? Тогда проверка теряет смысл: любой ответ программы покажется «ожидаемым». Правильный ответ находим заранее.
- Назови три этапа тестирования. Проверка в нормальных, в граничных (экстремальных) и в исключительных условиях.
- Какие данные для программы «дано число от 1 до 1000» будут граничными? 0 и 1 на нижней границе, 999 и 1000 на верхней. Число 0 заодно уже за границей допустимого.
Решаем упражнения
Практическая работа
№ 1 · «Практическая работа»
«Пересадка по маршруту». В Алматы вводят два автобусных маршрута. Остановки пронумерованы числами от 1 до 100. Первый автобус едет между остановками a и b, второй между c и d (направление может быть любым). Нужно найти, на скольких остановках можно пересесть с одного автобуса на другой. Образцы: 3 6 4 2 даёт 2, а 3 1 5 10 даёт 0.
Как думать. Каждый маршрут — это отрезок номеров остановок. Пересадка возможна на остановках, которые есть в обоих отрезках, то есть на пересечении. Сначала расставим концы по порядку (меньший, потом больший), потом найдём общий участок: он начинается с большего из левых концов и кончается меньшим из правых.
Решение. Подготовим данные для проверки заранее, до написания кода.
| № | Ввод a b c d | Что ждём | Этап |
|---|---|---|---|
| 1 | 8 5 6 9 | 3 | нормальный (оба маршрута «задом наперёд») |
| 2 | 50 10 20 30 | 11 | нормальный (один маршрут внутри другого) |
| 3 | 5 9 1 4 | 0 | нормальный (не пересекаются) |
| 4 | 10 20 20 30 | 1 | граничный (общая остановка только одна) |
| 5 | 7 7 7 7 | 1 | граничный (маршруты из одной остановки) |
| 6 | 1 100 100 1 | 100 | граничный (самые широкие маршруты) |
Вариант 1: с проверкой условий if (расставляем номера по порядку).
a, b, c, d = map(int, input().split())
if a > b:
a, b = b, a # первый маршрут: от меньшей остановки к большей
if c > d:
c, d = d, c # второй маршрут: то же самое
if a > c:
a, b, c, d = c, d, a, b # пусть первым будет тот, кто начинается раньше
if b > d:
b, d = d, b # теперь b - конец общего участка
if b < c:
print(0) # маршруты не пересекаются
else:
print(b - c + 1) # остановки от c до b
Вариант 2: короче, через функции min и max.
a, b, c, d = map(int, input().split())
a, b = min(a, b), max(a, b) # первый маршрут по возрастанию
c, d = min(c, d), max(c, d) # второй маршрут по возрастанию
left = max(a, c) # левый край общего участка
right = min(b, d) # правый край общего участка
print(max(0, right - left + 1)) # отрицательной длины не бывает
Обе программы запущены на тестах из таблицы и на образцах из задания: ответы 3, 11, 0, 1, 1, 100, а образцы 3 6 4 2 и 3 1 5 10 дали 2 и 0.
Ответ: количество пересадочных остановок равно max(0, min(b, d) - max(a, c) + 1) после упорядочивания концов каждого маршрута. Ожидаемые результаты по таблице тестов: 3, 11, 0, 1, 1, 100.
Анализ
№ 2 · «Анализ», вопрос 1
Сравни два способа записи программы «Пересадка по маршруту» (с цепочкой if и с min и max). Какая структура тебе понравилась больше? Объясни почему.
Как думать. Здесь нет одного «правильного» ответа. Важно назвать причину: длина, понятность, риск ошибиться.
Пример ответа. Мне больше понравился вариант с min и max. Он короче, а идея видна сразу: найти левый и правый край общего участка. В варианте с if много перестановок, и в них легко запутаться. Зато цепочку if проще объяснить новичку, который ещё не знает функций min и max.
Ответ: по выбору ученика с причиной, например: вариант с min и max короче и понятнее по идее, вариант с if нагляднее для начинающего.
№ 3 · «Анализ», вопрос 2
Образцы тестов из таблицы 1 учебника относятся к двум этапам проверки. Разложи их по группам в зависимости от условий.
Как думать. Если числа обычные, средние, и ответ «как в жизни», то это нормальные условия. Если данные на краях диапазона (остановки 1 и 100, маршруты едва касаются или совпадают), то граничные.
Решение. Тесты 1, 2 и 6 (1 2 3 4, 2 4 3 5, 1 99 97 100) проверяют края: маршруты стоят вплотную, пересекаются на пару остановок, доходят до остановки 1 или почти до 100. Тесты 3, 4 и 5 (35 17 10 42, 30 10 45 80, 4 50 4 50) — обычные «середины» диапазона.
Ответ: граничные: тесты 1, 2, 6; обычные (нормальные): тесты 3, 4, 5.
Вопросы для размышления
№ 4 · «Вопросы для размышления», вопрос 1
Что такое тестирование программы? Из каких этапов оно состоит?
Как думать. Сначала определение, потом три этапа по порядку.
Пример ответа. Тестирование — это проверка, совпадает ли результат работы программы с заранее известным ожидаемым результатом, на специально подобранных данных. Этапов три: проверка в нормальных условиях (обычные данные), в граничных (крайние значения) и в исключительных (данные, которые программа должна отклонить).
Ответ: проверка соответствия результата программы ожидаемому на подобранных данных; три этапа: нормальные, граничные, исключительные условия.
№ 5 · «Вопросы для размышления», вопрос 2
Как тестирование влияет на работоспособность программы?
Как думать. Подумай, что происходит с найденной ошибкой.
Пример ответа. Тест показывает, где программа ошибается. Мы находим причину, исправляем, запускаем тесты снова. Так программа становится надёжнее и работает правильно не только на «удобных» данных, но и на крайних и неожиданных.
Ответ: тестирование выявляет ошибки, после исправления программа работает надёжнее и правильно на более широком наборе данных.
№ 6 · «Вопросы для размышления», вопрос 3
В чём значимость тестирования программы?
Как думать. Что может случиться, если программу не проверять?
Пример ответа. Без тестов ошибка обнаружится у пользователя: неверный расчёт, сбой, потеря данных. Тестирование помогает заметить это заранее и убедиться, что программа отвечает условиям задачи. Чем важнее программа (банк, медицина, навигация), тем важнее проверка.
Ответ: тестирование позволяет найти ошибки до начала использования и убедиться, что программа соответствует условиям задачи.
Задание
№ 7 · «Задание», задание 1
⭐⭐ (средняя сложность. Дана шахматная доска, клетки которой определяются координатами (номер столбца и номер строки). Для двух клеток определи, одинакового ли они цвета. Если цвета одинаковые, выведи «Да», иначе «Нет». Подготовь 5 разных тестов с опорой на этапы тестирования. Образец: 2 1 3 2 даёт «Да».
Как думать. Клетки на доске чередуются, как на шахматке. Цвет клетки зависит от чётности суммы её координат: в одной клетке сумма x + y чётная, в соседней нечётная. Значит, клетки одного цвета, если суммы у них обе чётные или обе нечётные, то есть (x1 + y1) % 2 == (x2 + y2) % 2. Проверим на образце: 2 + 1 = 3 и 3 + 2 = 5, обе суммы нечётные, значит, цвет один и тот же.
Решение.
x1, y1, x2, y2 = map(int, input().split())
if (x1 + y1) % 2 == (x2 + y2) % 2:
print("Да")
else:
print("Нет")
Пять тестов (доска 8 × 8):
| № | Ввод x1 y1 x2 y2 | Ожидаем | Этап |
|---|---|---|---|
| 1 | 2 1 3 2 | Да | нормальный (образец) |
| 2 | 1 1 1 2 | Нет | нормальный (соседние клетки) |
| 3 | 1 1 8 8 | Да | граничный (противоположные углы) |
| 4 | 1 1 1 8 | Нет | граничный (углы на одном краю) |
| 5 | 5 5 5 5 | Да | граничный (одна и та же клетка) |
Все пять тестов запущены, ответы совпали с ожидаемыми. Для исключительных условий (координата 0, 9 или отрицательная) программа выше не готова: чтобы она сообщала об ошибке, перед сравнением нужна проверка if not (1 <= x1 <= 8 ...), как в примере со скидкой.
Ответ: (x1 + y1) % 2 == (x2 + y2) % 2 значит «Да», иначе «Нет».
Шпаргалка
Термины: тест, тестирование, ожидаемый (образцовый) результат, нормальные условия, граничные значения, исключительные условия.