gadget59.ru практика
Тестирование ПО · Практика 2 · 24 слайда

Практическая работа: модульное тестирование на Python и C++

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

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

Сегодня мы научимся писать модульные тесты (unit-тесты) на Python и C++.

🐍 Python ⚙️ C++ 🧪 pytest 🧩 assert 🤖 Автотесты
Мы напишем функции на Python и C++, а затем — тесты к ним. Вы сможете выбрать тот язык, который изучаете в своей группе.
Формат: практическая работа, 2 академических часа. Понадобится компьютер с установленным Python или компилятором C++.

Цель и задачи

Цель: получить практические навыки написания модульных тестов.

Что мы сделаем

  • 1 Напишем простую функцию (калькулятор).
  • 2 Напишем тесты для Python (pytest).
  • 3 Напишем тесты для C++ (assert).
  • 4 Запустим тесты и увидим результат.
  • 5 Специально сломаем код и посмотрим, как тесты это обнаружат.
В результате вы поймёте, как работают автотесты, и сможете писать их для своих проектов.

Что такое модульный тест

Модульный тест (unit test) — это программа, которая проверяет работу отдельной функции или метода.

Аналогия. Представьте, что вы купили конструктор. Каждая деталь должна быть исправна. Модульный тест — это проверка одной детали: «подходит ли этот винт к этой гайке?». Если все детали проверены — можно собирать.
СвойствоЧто значит Изолированностьтест проверяет только одну функцию Автоматичностьзапускается одной командой Быстротавыполняется за миллисекунды Повторяемостьможно запускать сколько угодно раз
Модульные тесты — это «первая линия обороны». Они ловят ошибки в самом начале, когда исправить их дешевле всего.

Наша функция: калькулятор

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

Python

def add(a, b): return a + b def sub(a, b): return a - b def mul(a, b): return a * b def div(a, b): if b == 0: raise ValueError("Деление на ноль") return a / b

C++

int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int mul(int a, int b) { return a * b; } double div(int a, int b) { if (b == 0) throw std::invalid_argument("Деление на ноль"); return (double)a / b; }
Обратите внимание: функция деления специально выбрасывает исключение при делении на ноль. Это правильное поведение — мы будем его тестировать.

Установка pytest (Python)

Для Python мы будем использовать библиотеку pytest — популярный фреймворк для тестирования.

Установка

# Откройте терминал (командную строку) и введите: pip install pytest
Если установка прошла успешно — можно писать тесты. Проверить можно командой pytest --version.

Что такое фреймворк

Фреймворк (framework) — это набор готовых инструментов и правил, которые упрощают разработку. pytest берёт на себя поиск тестов, их запуск и вывод результатов.

Структура проекта на Python

Создадим два файла: один с функциями, другой — с тестами.

// Структура проекта calculator/ ├── calc.py # функции калькулятора └── test_calc.py # тесты для них
ФайлЧто содержит calc.pyфункции add, sub, mul, div test_calc.pyтесты для этих функций
pytest автоматически находит файлы, имя которых начинается с test_, и запускает все функции, имя которых тоже начинается с test_.

Пишем первый тест на Python

Вот как выглядит простейший тест для функции add.

# test_calc.py from calc import add, sub, mul, div import pytest def test_add_positive(): # Проверяем, что 3 + 5 = 8 assert add(3, 5) == 8 def test_add_negative(): # Проверяем, что -3 + (-5) = -8 assert add(-3, -5) == -8 def test_add_zero(): # Проверяем, что 0 + 7 = 7 assert add(0, 7) == 7
assert — это ключевое слово Python. Оно проверяет, что условие истинно. Если условие ложно — тест падает с ошибкой.
Запуск: pytest. Если всё хорошо — увидите зелёные точки. Если нет — красные и сообщение об ошибке.

Тестируем исключения на Python

Функция div выбрасывает исключение при делении на ноль. Как это проверить?

# test_calc.py def test_div_by_zero(): # Проверяем, что при делении на ноль выбрасывается ValueError with pytest.raises(ValueError): div(5, 0)
КонструкцияЧто значит pytest.raises(ValueError)ожидаем исключение типа ValueError with ...:внутри блока выполняется код
Если исключение действительно выброшено — тест пройден. Если нет — тест падает. Это правильный способ тестировать ошибки.

Полный набор тестов на Python

Соберём все тесты для нашего калькулятора.

# test_calc.py from calc import add, sub, mul, div import pytest def test_add(): assert add(3, 5) == 8 assert add(-3, -5) == -8 assert add(0, 7) == 7 def test_sub(): assert sub(10, 4) == 6 assert sub(4, 10) == -6 def test_mul(): assert mul(3, 4) == 12 assert mul(0, 5) == 0 def test_div(): assert div(10, 2) == 5 with pytest.raises(ValueError): div(5, 0)
Запуск: pytest. Если все тесты пройдены — вы увидите 4 зелёные точки. Это значит, что ваш код работает правильно.

Тестирование на C++

В C++ нет встроенного фреймворка для тестирования, но есть assert — макрос, который проверяет условие.

#include <iostream> #include <cassert> int main() { // Проверяем, что 3 + 5 = 8 assert(add(3, 5) == 8); // Проверяем, что -3 + (-5) = -8 assert(add(-3, -5) == -8); std::cout << "Все тесты пройдены!" << std::endl; return 0; }
assert в C++ — это макрос. Если условие ложно — программа аварийно завершается с сообщением. Если истинно — продолжает работу.
Важно: assert работает только в отладочной сборке. В релизной сборке он может быть отключён. Для серьёзных проектов используют специальные фреймворки (Catch2, Google Test).

Полный набор тестов на C++

Соберём тесты для всех операций.

#include <iostream> #include <cassert> #include <stdexcept> int main() { // Сложение assert(add(3, 5) == 8); assert(add(-3, -5) == -8); // Вычитание assert(sub(10, 4) == 6); assert(sub(4, 10) == -6); // Умножение assert(mul(3, 4) == 12); assert(mul(0, 5) == 0); // Деление assert(div(10, 2) == 5.0); // Деление на ноль — ожидаем исключение try { div(5, 0); assert(false); // если сюда дошли — тест провален } catch (const std::invalid_argument&) { // всё хорошо, исключение выброшено } std::cout << "Все тесты пройдены!" << std::endl; return 0; }
Компиляция: g++ -std=c++17 test.cpp calc.cpp -o test. Запуск: ./test. Если увидите «Все тесты пройдены!» — отлично.

Специально ломаем код

Чтобы убедиться, что тесты работают, давайте специально сломаем функцию add.

# Было: def add(a, b): return a + b # Стало (специально с ошибкой): def add(a, b): return a - b # ошибка: вместо плюса минус

Что произойдёт?

При запуске pytest вы увидите красную ошибку:

FAILED test_calc.py::test_add - assert -5 == 8
Это значит, что тест сработал. Он обнаружил ошибку. Если бы тестов не было, вы могли бы не заметить эту проблему.
После проверки верните правильный код обратно. Так вы убедитесь, что тесты работают в обе стороны.

Самостоятельные задания

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

Задание 1

Напишите тест для функции sub, который проверяет вычитание нуля: 5 - 0 = 5.

Задание 2

Напишите тест для функции mul, который проверяет умножение на отрицательное число: 3 * (-4) = -12.

Задание 3

Напишите тест для функции div, который проверяет деление на ноль (ожидается исключение).

Задание 4

Специально сломайте любую функцию и убедитесь, что тест обнаружил ошибку.

Не бойтесь ошибаться. Главное — понять принцип: тест проверяет, что код работает так, как задумано.

Шаблон для отчёта

Оформите результаты работы в виде отчёта.

// Отчёт по практической работе // 1. Титульный лист ФИО, группа, дата, название работы // 2. Цель работы Получить навыки написания модульных тестов // 3. Код функций (калькулятор) ... // 4. Код тестов ... // 5. Результаты запуска Все тесты пройдены (скриншот) // 6. Эксперимент с ошибкой Что сломали, как тест обнаружил ошибку // 7. Вывод Что получилось, какие навыки приобрели
Отчёт сдаётся в электронном виде. Код можно оформить в текстовом файле или в виде скриншотов.

Критерии оценки

Как будет оцениваться практическая работа.

КритерийЧто проверяетсяБаллы Код функцийПравильность, читаемость3 Код тестовПокрытие всех операций, включая деление на ноль5 ЗапускВсе тесты пройдены, результат записан4 ЭкспериментСломали код, тест обнаружил ошибку4 ОформлениеОтчёт по шаблону, аккуратность2 ВыводСформулированы результаты, сделаны выводы2
Оценка «5» (отлично): 18–20 баллов.
Оценка «4» (хорошо): 14–17 баллов.
Оценка «3» (удовлетворительно): 10–13 баллов.

Советы по написанию тестов

Несколько практических советов, которые помогут писать хорошие тесты.

  • Один тест — одна проверка. Не смешивайте несколько проверок в одной функции.
  • Имя теста должно говорить о том, что он проверяет. Например, test_add_positive_numbers.
  • Проверяйте граничные значения. Ноль, максимум, минимум.
  • Проверяйте исключения. Если функция может выбросить ошибку — проверьте это.
  • Запускайте тесты после каждого изменения. Это поможет сразу заметить проблему.
Хорошие тесты — это инвестиция. Чем больше тестов, тем увереннее вы можете менять код, не боясь что-то сломать.

Итоги практики

Подведём итоги. Вот что вы освоили.

  • ✅ Модульный тест — это программа, которая проверяет функцию.
  • ✅ pytest — фреймворк для тестирования на Python.
  • ✅ assert — ключевое слово (Python) или макрос (C++), который проверяет условие.
  • ✅ pytest.raises — способ проверить, что функция выбрасывает исключение.
  • ✅ Сломанный код обнаруживается тестами — это доказывает их пользу.
  • ✅ Автотесты — это быстрый и надёжный способ проверки кода.
Теперь вы умеете писать автоматические тесты. Это навык, который отличает профессионального разработчика от новичка.

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

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

  1. Допишите тесты для всех операций калькулятора (сложение, вычитание, умножение, деление).
  2. Оформите отчёт по шаблону.
  3. Напишите тест для функции «остаток от деления» (добавьте её в калькулятор).
  4. Попробуйте использовать фреймворк unittest (встроенный в Python) вместо pytest.
  5. Для C++: попробуйте подключить фреймворк Catch2 и написать тесты с его помощью.
Если задание кажется сложным — разбейте его на части. Сначала тесты для одной операции, потом для другой.

Что дальше?

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

  • Лекция 4: покрытие кода и метрики (MC/DC).
  • Практика 3: интеграционное тестирование.
  • Лекция 5: отладка и инструменты разработчика.
Автоматические тесты — это основа современной разработки. Без них невозможно представить ни один серьёзный проект.

Спасибо за работу!

🧪

Тесты — это ваша страховка от ошибок

Чем раньше вы начнёте писать тесты, тем увереннее будете себя чувствовать при изменении кода. Это привычка, которая окупается сторицей.

🐍 Python ⚙️ C++ 🧪 pytest 🚀 автотесты