← Назад к вопросам

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

2.3 Middle🔥 171 комментариев
#Soft skills и карьера#Теория тестирования

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое фикстуры (fixtures) в pytest?

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

Главная цель фикстур — повышение читаемости, поддержки и повторного использования кода тестов путем выноса общих подготовительных и завершающих операций из тела тестовых функций.

Основные характеристики и принцип работы

  1. Декларативный доступ: Фикстура не вызывается напрямую. Тест запрашивает её, указав имя фикстуры в списке параметров тестовой функции. Pytest автоматически находит и исполняет соответствующую фикстуру, а результат её работы (так называемый возвращаемый объект) передается в тест в качестве аргумента.

  2. Гибкая область видимости (Scope): Это критически важная настройка, управляющая жизненным циклом фикстуры. Она определяет, как часто фикстура будет создаваться и уничтожаться:

    *   **`function`** (по умолчанию): Фикстура создается заново для *каждого* теста.
    *   **`class`**:** Создается один раз для всего тестового класса.
    *   **`module`**:** Создается один раз для модуля (файла с тестами).
    *   **`package`**:** Создается один раз для пакета.
    *   **`session`**:** Создается один раз за всю сессию выполнения тестов (например, для подключения к базе данных).

  1. Гарантированная очистка (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.

Что такое фикстуры в pytest? | PrepBro