Что такое фикстуры в pytest?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое фикстуры (fixtures) в pytest?
Фикстуры в pytest — это один из ключевых и мощнейших механизмов фреймворка, предназначенный для подготовки, предоставления и последующей очистки тестовых данных, состояния системы или внешних зависимостей перед выполнением тестов и после него. Если проводить аналогию, то фикстура — это надежный и конфигурируемый «ассистент», который делает за тестировщика всю рутинную работу по настройке тестового окружения.
Главная цель фикстур — повышение читаемости, поддержки и повторного использования кода тестов путем выноса общих подготовительных и завершающих операций из тела тестовых функций.
Основные характеристики и принцип работы
-
Декларативный доступ: Фикстура не вызывается напрямую. Тест запрашивает её, указав имя фикстуры в списке параметров тестовой функции. Pytest автоматически находит и исполняет соответствующую фикстуру, а результат её работы (так называемый возвращаемый объект) передается в тест в качестве аргумента.
-
Гибкая область видимости (Scope): Это критически важная настройка, управляющая жизненным циклом фикстуры. Она определяет, как часто фикстура будет создаваться и уничтожаться:
* **`function`** (по умолчанию): Фикстура создается заново для *каждого* теста.
* **`class`**:** Создается один раз для всего тестового класса.
* **`module`**:** Создается один раз для модуля (файла с тестами).
* **`package`**:** Создается один раз для пакета.
* **`session`**:** Создается один раз за всю сессию выполнения тестов (например, для подключения к базе данных).
- Гарантированная очистка (Finalizer): Фикстуры поддерживают надежную очистку ресурсов (закрытие соединений, удаление временных файлов) с помощью конструкции
yield. Код, написанный послеyield, выполняется после завершения теста, независимо от его результата (успех, провал, ошибка).
Практические примеры
Рассмотрим классический пример: тестирование работы с базой данных.
Пример 1: Базовая фикстура с yield
# conftest.py или в файле с тестами
import pytest
import sqlite3
from pathlib import Path
@pytest.fixture(scope="function")
def temporary_db():
"""Создает временную базу данных в памяти для каждого теста."""
# Setup (Подготовка) - код ДО теста
connection = sqlite3.connect(":memory:")
cursor = connection.cursor()
cursor.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
cursor.execute("INSERT INTO users (name) VALUES ('Alice')")
connection.commit()
# Передаем объект соединения тесту
yield cursor
# Teardown (Очистка) - код ПОСЛЕ теста
cursor.close()
connection.close()
print("\nСоединение с БД закрыто.")
# test_example.py
def test_user_count(temporary_db): # Запрос фикстуры по имени
temporary_db.execute("SELECT COUNT(*) FROM users")
count = temporary_db.fetchone()[0]
assert count == 1
def test_user_name(temporary_db):
# Для этого теста будет создано НОВОЕ соединение и БД
temporary_db.execute("SELECT name FROM users WHERE id=1")
name = temporary_db.fetchone()[0]
assert name == 'Alice'
Пример 2: Фикстура с областью видимости session для тяжелых ресурсов
@pytest.fixture(scope="session")
def docker_redis_client():
"""Запускает контейнер Redis один раз на всю сессию тестов."""
import docker
client = docker.from_env()
container = client.containers.run("redis:alpine", detach=True, ports={'6379/tcp': 6379})
# Ждем, пока Redis станет доступен
import time
time.sleep(2)
yield container # Контейнер передается тестам
# Останавливаем и удаляем контейнер после всех тестов
container.stop()
container.remove()
Пример 3: Фикстуры как "фабрики" данных
Фикстуры могут возвращать не только готовые объекты, но и функции для их создания (паттерн Factory).
@pytest.fixture
def new_user_factory():
"""Фикстура-фабрика. Возвращает функцию для создания пользователя."""
def _create_user(name="TestUser", is_admin=False):
return {
"username": name,
"email": f"{name.lower()}@example.com",
"is_active": True,
"role": "admin" if is_admin else "user"
}
return _create_user # Возвращаем саму функцию, а не словарь
def test_factory_usage(new_user_factory):
user1 = new_user_factory() # Создаем стандартного пользователя
assert user1["role"] == "user"
user2 = new_user_factory("AdminBob", is_admin=True) # Создаем админа с кастомным именем
assert user2["role"] == "admin"
assert user2["username"] == "AdminBob"
Продвинутые возможности
- Автоиспользование (
autouse=True): Фикстура выполняется автоматически для всех тестов в её области видимости, даже без явного запроса в параметрах. - Зависимости фикстур: Фикстуры могут сами запрашивать другие фикстуры, позволяя строить сложные, но читаемые цепочки подготовки.
- Динамическая область видимости: Область видимости может быть определена динамически, на основе контекста.
- Параметризация фикстур: С помощью
@pytest.fixture(params=[...])можно создать одну фикстуру, которая будет запускать тест multiple times с разными предоставляемыми данными.
Итог
Фикстуры — это фундаментальный механизм pytest для управления тестовым контекстом и зависимостями. Они позволяют:
- Изолировать тесты, обеспечивая предсказуемое начальное состояние.
- Эффективно управлять дорогостоящими ресурсами (БД, сетевые соединения).
- Устранить дублирование кода.
- Делать тесты чище, сосредоточенными только на логике проверки (принцип Arrange-Act-Assert).
Правильное использование фикстур — признак зрелого и поддерживаемого тестового набора в экосистеме Python.