МУНИЦИПАЛЬНОЕ АВТОНОМНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ДОПОЛНИТЕЛЬНОГО ОБРАЗОВАНИЯ
«ЦЕНТР ДЕТСКОГО ТЕХНИЧЕСКОГО ТВОРЧЕСТВА»
Методическая разработка
«Тестирование данных с помощью библиотеки Pytest»
к дополнительной общеобразовательной
общеразвивающей программе
технической направленности
«Программирование на Python»
Возраст детей: 10-17 лет
Автор: Костычев Вадим Александрович
г. Заречный Пензенской области
2025 г.
В рамках изучения Python мы углубляемся в тему тестирования программного обеспечения с помощью библиотеки pytest — одного из самых мощных и гибких инструментов для автоматизации тестирования. pytest позволяет эффективно проверять корректность работы кода, от простых функций до сложных приложений, что делает его незаменимым в современной разработке.
Тестирование является важнейшим этапом разработки программного обеспечения, так как помогает:
Обнаруживать ошибки на ранних этапах.
Убедиться, что изменения в коде не нарушают существующий функционал.
Документировать требования к системе через тесты.
Изучение pytest станет важным шагом на пути к освоению профессиональной разработки, где качество кода и надежность системы играют ключевую роль.
Целью данной методической разработки является обучение написанию и использованию автоматических тестов с помощью библиотеки pytest . Учащиеся должны освоить:
Создание базовых тестов с использованием утверждений (assert).
Использование фикстур для подготовки данных.
Параметризацию тестов для проверки множества сценариев.
Данная методическая разработка используется как обучающий пример для работы по дополнительной общеобразовательной общеразвивающей программе технической направленности «Программирование на Python». С их помощью учащиеся смогут применить теоретические знания на практике, научатся писать качественные и надежные программы, а также подготовятся к работе в команде над реальными проектами.
В современном мире программирования надежность и качество кода играют ключевую роль. Программное обеспечение становится все сложнее, а требования к его стабильности — строже. Именно поэтому тестирование является неотъемлемой частью процесса разработки. Оно позволяет разработчикам быть уверенными в том, что их код работает корректно, обнаруживать ошибки на ранних этапах и предотвращать их появление в будущем.
В рамках изучения Python мы углубляемся в тему тестирования с использованием библиотеки pytest — одного из самых мощных и гибких инструментов для автоматизации тестирования. pytest выделяется среди других фреймворков своей простотой, удобством использования и широким набором функций. Он позволяет писать как простые тесты для отдельных функций, так и сложные сценарии для проверки взаимодействия различных компонентов системы.
Тестирование с помощью pytest помогает:
обнаруживать ошибки: тесты позволяют быстро находить проблемы в коде до того, как они попадут в продакшен.
защищать код от регрессий: при внесении изменений тесты гарантируют, что существующий функционал продолжает работать корректно.
документировать требования: тесты служат живой документацией, которая показывает, как должен работать код.
ускорять разработку: автоматизированные тесты экономят время, которое могло бы быть потрачено на ручную проверку.
Изучение pytest станет важным шагом на пути к освоению профессиональной разработки. Это особенно актуально для тех, кто планирует работать с большими проектами, где качество кода напрямую влияет на успех продукта. Библиотека pytest используется во множестве компаний и проектов, что делает ее навык ценным для будущих разработчиков.
Автоматическое обнаружение тестов
pytest автоматически находит тесты в файлах, которые начинаются с test_ или заканчиваются на _test.py. Например:
test_example.py
example_test.py
Тестовые функции также должны начинаться с test_.
# test_example.py
def test_addition():
assert 1 + 1 == 2
Запуск:
pytest
Простой тест
Простые тесты — это основа тестирования. Они проверяют корректность работы отдельных функций или методов. В данном случае мы тестируем функцию add, которая выполняет сложение двух чисел.
Такие тесты важны для:
Проверки базовой функциональности.
Обнаружения ошибок в простых операциях.
Убедиться, что изменения в коде не ломают существующий функционал.
Мы используем утверждения (assert) для проверки ожидаемого результата. Например:
assert add(2, 3) == 5 проверяет, что сумма 2 и 3 равна 5.
Для чисел с плавающей точкой используется pytest.approx, так как они могут содержать небольшие погрешности из-за особенностей хранения данных.
import pytest
def add(a, b):
# Функция для сложения двух чисел
return a + b
def test_add():
# Тест проверяет корректность работы функции add
assert add(2, 3) == 5 # Проверяем, что 2 + 3 = 5
assert add(-1, 1) == 0 # Проверяем, что -1 + 1 = 0
assert add(0.1, 0.2) == pytest.approx(0.3) # Для чисел с плавающей точкой используем pytest.approx
if __name__ == '__main__':
pytest.main([t]) # Запускаем тесты в этом файле
Тестирование исключений
Тестирование исключений позволяет убедиться, что программа корректно обрабатывает ошибки. Например, деление на ноль — это типичная ошибка, которая может возникнуть в реальных приложениях.
В этом тесте мы проверяем:
Корректное выполнение операции (например, divide(10, 2) должно вернуть 5).
Проверку, что при делении на ноль вызывается исключение ValueError.
Использование pytest.raises позволяет нам убедиться, что исключение действительно возникает, и программа не завершается с ошибкой. Это важно для написания надежного кода, который может корректно обрабатывать ошибки.
import pytest
def divide(a, b):
# Функция деления. Вызывает исключение при делении на ноль
if b == 0:
raise ValueError("Деление на ноль")
return a / b
def test_divide():
# Тест проверяет корректность деления
assert divide(10, 2) == 5 # Проверяем, что 10 / 2 = 5
# Проверяем, что при делении на ноль вызывается исключение ValueError
with pytest.raises(ValueError): # pytest.raises проверяет, что указанное исключение было вызвано
divide(10, 0)
if __name__ == '__main__':
import pytest
pytest.main([f]) # Запускаем тесты в этом файле
Фикстуры
Теория
Фикстуры — это функции, которые подготавливают данные или ресурсы для тестов. Они помогают:
Упростить повторяющиеся операции (например, создание списка или подключение к базе данных).
Очистить ресурсы после выполнения теста (например, удалить временные файлы).
В данном примере фикстура sample_data возвращает список чисел [1, 2, 3]. Этот список используется в тесте test_sum для проверки суммы элементов.
Фикстуры особенно полезны в более сложных сценариях, таких как работа с базами данных или внешними API, где нужно подготовить данные перед тестированием.
import pytest
@pytest.fixture
def sample_data():
# Фикстура возвращает список чисел для тестов
return [1, 2, 3]
def test_sum(sample_data):
# Тест проверяет сумму элементов списка
assert sum(sample_data) == 6 # Проверяем, что сумма [1, 2, 3] равна 6
if __name__ == '__main__':
import pytest
pytest.main([f]) # Запускаем тесты в этом файле
Фикстуры с настройкой и очисткой
Теория
Фикстуры с настройкой и очисткой позволяют выполнять дополнительные действия до и после теста. Это важно для:
Создания временных файлов, баз данных или других ресурсов.
Очистки ресурсов после завершения теста, чтобы не оставлять "мусор" (например, временные файлы).
В данном примере фикстура temp_file:
Создает временный файл с данными.
Возвращает имя файла для использования в тесте.
Удаляет файл после завершения теста.
Этот подход гарантирует, что тесты не зависят друг от друга и не влияют на состояние системы.
import pytest
@pytest.fixture
def temp_file():
# Создаем временный файл с данными
file_name = "temp.txt"
with open(file_name, "w") as f:
f.write("Test data")
# Возвращаем имя файла для использования в тесте
yield file_name # yield позволяет выполнить код после теста
# Очистка: удаляем временный файл после завершения теста
import os
os.remove(file_name)
def test_file_read(temp_file):
# Тест проверяет содержимое временного файла
with open(temp_file, "r") as f:
assert f.read() == "Test data" # Проверяем, что файл содержит "Test data"
if __name__ == '__main__':
import pytest
pytest.main([f]) # Запускаем тесты в этом файле
Параметризация тестов
Параметризация позволяет запускать один тест с разными входными данными. Это полезно для:
Сокращения дублирования кода.
Проверки множества сценариев без написания отдельных тестов.
В данном примере тест test_add проверяет сложение чисел для трех различных случаев:
Положительные числа (2 + 3 = 5).
Числа с разными знаками (-1 + 1 = 0).
Числа с плавающей точкой (0.1 + 0.2 ≈ 0.3).
Параметризация делает тесты более гибкими и масштабируемыми, особенно когда нужно протестировать большое количество входных данных.
import pytest
@pytest.mark.parametrize("a, b, expected", [
(2, 3, 5), # Проверяем, что 2 + 3 = 5
(-1, 1, 0), # Проверяем, что -1 + 1 = 0
(0.1, 0.2, 0.3), # Проверяем, что 0.1 + 0.2 ≈ 0.3
])
def test_add(a, b, expected):
# Тест проверяет функцию add с разными параметрами
assert a + b == pytest.approx(expected) # pytest.approx используется для сравнения чисел с плавающей точкой
if __name__ == '__main__':
import pytest
pytest.main([f]) # Запускаем тесты в этом файле
Моки и патчи
Теория
Моки (mocks) используются для имитации объектов или функций, которые взаимодействуют с внешними системами (например, базами данных, API). Это важно для:
Изоляции тестируемого кода от внешних зависимостей.
Ускорения тестов (внешние системы могут быть медленными).
Тестирования сценариев, которые сложно воспроизвести в реальной среде.
В данном примере мы мокаем функцию get_current_user, чтобы она возвращала заранее заданный результат. Это позволяет протестировать функцию, не обращаясь к реальной базе данных.
from unittest.mock import patch
# Функция, которую мы будем тестировать
def get_current_user():
"""
Сложная функция, которая обращается к базе данных.
В реальном приложении она могла бы выполнять запрос к БД или внешнему API.
"""
return {"id": 1, "name": "Alice"}
def test_get_current_user():
"""
Тест проверяет, что функция get_current_user возвращает ожидаемый результат.
Мы используем мок, чтобы заменить реальную функцию на имитацию (mock), которая возвращает заранее заданный результат.
"""
# Создаем мок-ответ для функции get_current_user
mock_user = {"id": 2, "name": "Bob"}
# Используем patch для замены функции get_current_user на мок
with patch("t.get_current_user", return_value=mock_user): # Заменяем реальную функцию на мок
# Вызываем функцию
user = get_current_user()
# Проверяем результат
assert user["name"] == "Bob" # Проверяем, что имя пользователя равно "Bob"
if __name__ == '__main__':
import pytest
pytest.main([f]) # Запускаем тесты в этом файле
Тестирование API
Тестирование API — это проверка взаимодействия с внешними сервисами через HTTP-запросы. Это важно для:
Убедиться, что API работает корректно.
Проверить статус-коды, заголовки и формат данных в ответе.
В данном примере мы тестируем запрос к GitHub API:
Проверяем, что статус-код ответа равен 200 (OK).
Проверяем, что в заголовках указан тип контента JSON.
Такие тесты помогают убедиться, что ваше приложение корректно взаимодействует с внешними сервисами.
import requests
def test_github_api():
# Тест проверяет ответ от GitHub API
response = requests.get("https://api.github.com") # Отправляем GET-запрос к GitHub API
# Проверяем статус-код ответа
assert response.status_code == 200 # Ожидаем статус-код 200 (OK)
# Проверяем, что в заголовках указан тип контента JSON
assert "application/json" in response.headers["Content-Type"]
if __name__ == '__main__':
import pytest
pytest.main([f]) # Запускаем тесты в этом файле