Что такое фикстуры в Pytest

Ответ

Фикстуры (fixtures) в pytest — это специальные функции, предназначенные для подготовки тестового окружения, предоставления данных или ресурсов для тестов, а также для выполнения очистки (teardown) после их завершения. Они являются центральным элементом архитектуры pytest для создания модульных, переиспользуемых и легко поддерживаемых тестов.

Почему фикстуры предпочтительнее? Фикстуры решают проблемы, присущие традиционным методам setup/teardown (например, setUp/tearDown в unittest):

  • Явные зависимости: Тесты явно объявляют, какие фикстуры им нужны, просто указывая их как аргументы функции. Это делает тесты более читаемыми и понятными.
  • Переиспользование: Фикстуры могут быть легко переиспользованы множеством тестов и даже в других фикстурах, что значительно сокращает дублирование кода.
  • Модульность и инверсия управления: pytest сам управляет жизненным циклом фикстур, создавая их по требованию и уничтожая после использования, что упрощает написание тестов.
  • Гибкость: Поддерживают различные области видимости (scope) и параметризацию.

Основные особенности:

  • Объявление: Фикстуры объявляются с помощью декоратора @pytest.fixture.
  • Инъекция: Они передаются в тестовые функции или другие фикстуры как обычные аргументы.
  • Область видимости (Scope): Определяет, как часто фикстура будет создаваться и уничтожаться:
    • function (по умолчанию): Выполняется один раз для каждого тестового вызова.
    • class: Выполняется один раз для каждого тестового класса.
    • module: Выполняется один раз для каждого модуля.
    • session: Выполняется один раз за всю тестовую сессию.
  • Setup и Teardown: Для выполнения операций очистки используется ключевое слово yield. Код до yield выполняется как setup, а код после yield — как teardown. Если yield не используется, фикстура просто возвращает значение.

Пример:

import pytest

# Фикстура, предоставляющая объект пользователя
@pytest.fixture(scope="function")
def user_data():
    """Фикстура, создающая данные пользователя для каждого теста."""
    print("n[SETUP] Создание пользователя...")
    user = {"id": 1, "name": "Alice", "email": "alice@example.com"}
    yield user  # Передача данных в тест
    print(f"[TEARDOWN] Удаление пользователя {user['name']}...")

# Фикстура, зависящая от user_data
@pytest.fixture(scope="session")
def db_connection():
    """Фикстура, имитирующая подключение к БД, создаётся один раз за сессию."""
    print("n[SETUP] Установка соединения с БД...")
    conn = "Database Connection Object"
    yield conn
    print("[TEARDOWN] Закрытие соединения с БД.")

def test_user_name(user_data, db_connection):
    """Тест, использующий фикстуры user_data и db_connection."""
    print(f"Тест: Проверка имени пользователя. Используется БД: {db_connection}")
    assert user_data["name"] == "Alice"

def test_user_email(user_data):
    """Другой тест, использующий только user_data."""
    print("Тест: Проверка email пользователя.")
    assert "example.com" in user_data["email"]

# Для запуска: pytest -s your_test_file.py

Дополнительные возможности:

  • Параметризация: Фикстуры могут быть параметризованы с помощью @pytest.mark.parametrize или pytest.fixture(params=...), что позволяет запускать один и тот же тест с разными наборами входных данных.
  • Автоматическое использование: Фикстуры могут быть автоматически применены ко всем тестам в определённой области видимости с помощью autouse=True.
  • Переопределение: Фикстуры могут быть переопределены в более узких областях видимости, что полезно для настройки поведения тестов.