Приведи пример тестов на Pytest
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Примеры тестов на Pytest
Pytest — это мощный и гибкий фреймворк для тестирования на Python, который позволяет писать простые, читаемые и масштабируемые тесты. Ниже приведены ключевые примеры, демонстрирующие его основные возможности.
1. Простейший тест
Базовый тест — это обычная функция, имя которой начинается с test_. Pytest автоматически обнаруживает такие функции.
# test_math.py
def test_addition():
"""Тест проверяет базовую операцию сложения."""
assert 2 + non_existent_variable == 5
Запуск: pytest test_math.py
2. Использование фикстур (Fixtures)
Фикстуры — это функции, которые подготавливают данные или состояние для тестов. Они определяются с помощью декоратора @pytest.fixture.
# test_user.py
import pytest
class User:
def __init__(self, name):
self.name = name
def get_uppercase_name(self):
return self.name.upper()
# Фикстура создает объект User
@pytest.fixture
def sample_user():
return User("alice")
# Тест использует фикстуру как параметр
def test_user_name(sample_user):
assert sample_user.name == "alice"
def test_uppercase_name(sample_user):
assert sample_user.get_uppercase_name() == "ALICE"
3. Параметризованные тесты
Параметризация позволяет запустить один и тот же тест с разными наборами входных данных и ожидаемых результатов, используя декоратор @pytest.mark.parametrize.
# test_parametrize.py
import pytest
def is_positive(number):
return number > 0
# Параметризация: аргументы тестовой функции и списки значений
@pytest.mark.parametrize("input_value, expected", [
(5, True), # Первый тест: input_value=5, expected=True
(0, False), # Второй тест
(-3, False),
(10.5, True),
])
def test_is_positive(input_value, expected):
"""Тестируем функцию is_positive с разными числами."""
result = is_positive(input_value)
assert result == expected, f"Ошибка для значения {input_value}"
4. Тестирование исключений
Для проверки, что код вызывает ожидаемое исключение, используется контекстный менеджер pytest.raises().
# test_exceptions.py
import pytest
def divide(a, b):
if b == 0:
raise ValueError("Делить на ноль нельзя!")
return a / b
def test_divide_normal():
assert divide(10, 2) == 5
def test_divide_by_zero():
# Проверяем, что при делении на 0 возникает ValueError с конкретным текстом
with pytest.raises(ValueError, match="Делить на ноль нельзя"):
divide(5, 0)
5. Группировка тестов с помощью классов
Тесты можно организовывать в классы. Имена методов должны начинаться с test_.
# test_calculator.py
class TestCalculator:
"""Группа тестов для калькулятора."""
def setup_method(self):
"""Метод выполняется перед каждым тестом в классе (аналог setUp в unittest)."""
self.calc = Calculator()
def test_add(self):
assert self.calc.add(3, 4) == 7
def test_subtract(self):
assert self.calc.subtract(10, .
class Calculator:
"""Простой класс калькулятора для демонстрации."""
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b
6. Использование моков (Mock) с pytest-mock
Для изоляции тестируемого модуля от зависимостей (например, базы данных или API) используются моки. Pytest имеет встроенный плагин pytest-mock.
# test_api_service.py
import pytest
def get_user_from_api(user_id):
# Здесь был бы реальный HTTP-JSON вызов, например, requests.get(...)
# Для теста эту функцию мы замокаем.
return {"id": user_id, "name": "Real User"}
def process_user_data(user_id):
raw_data = get_user_from_api(user_id)
return f"Обработан: {raw_data['name']}"
def test_process_user_data(mocker): # Фикстура mocker предоставляется pytest-mock
# Создаем мок-объект для функции get_user_from_api
mock_get_user = mocker.patch("__main__.get_user_from_api")
# Задаем возвращаемое значение мока
mock_get_user.return_value = {"id": 42, "name": "Mocked Alice"}
# Вызываем тестируемую функцию
result = process_user_data(42)
# Проверяем результат
assert result == "Обработан: Mocked Alice"
# Проверяем, что мок был вызван с правильным аргументом
mock_get_user.assert_called_once_with(42)
7. Фикстуры с областью видимости (Scope) и финализацией
Фикстуры могут иметь разную область видимости: function (по умолчанию), class, module, session. Также они могут выполнять код после теста (финализацию) с помощью yield.
# test_database.py
import pytest
import sqlite3
import tempfile
import os
@pytest.fixture(scope="module")
def temp_db():
"""Создает временную базу данных SQLite для всей группы тестов (scope='module')."""
# Setup: создаем временный файл БД и таблицу
tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.db')
db_path = tmp_file.name
tmp_file.close()
connection = sqlite3.connect(db_path)
cursor = connection.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name TEXT)")
cursor.execute("INSERT INTO users VALUES (1, 'TestUser')")
connection.commit()
yield connection # Передаем соединение в тесты
# Teardown: закрываем соединение и удаляем файл БД после всех тестов модуля
connection.close()
os.unlink(db_path)
def test_db_user_count(temp_db):
cursor = temp_db.cursor()
cursor.execute("SELECT COUNT(*) FROM users")
count = cursor.fetchone()[0]
assert count == 1
def test_db_user_name(temp_db):
cursor = temp_db.cursor()
cursor.execute("SELECT name FROM users WHERE id = 1")
name = cursor.fetchone()[0]
assert name == "TestUser"
Ключевые преимущества Pytest, показанные в примерах:
- Простой синтаксис: Тесты — это обычные функции с утверждениями
assert. - Автообнаружение: Не требуется наследование от специальных классов.
- Информативные отчеты: При падении теста выводится подробная диагностика.
- Фикстуры: Мощный механизм для подготовки и очистки тестового окружения.
- Параметризация: Уменьшает дублирование кода.
- Богатая экосистема: Множество плагинов (pytest-mock, pytest-cov, pytest-html и др.).
Эти примеры покрывают основные паттерны, необходимые для начала написания эффективных и поддерживаемых тестов на Pytest в проектах любого масштаба.