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

Когда вызывается фикстура?

2.0 Middle🔥 141 комментариев
#Другое

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

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

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

Когда вызывается фикстура в Pytest?

Фикстуры (fixtures) в Pytest — это мощный механизм для предоставления данных, состояния или ресурсов тестам. Их вызов зависит от области видимости (scope) и способа их объявления в тестовых функциях или классах. Понимание времени вызова критически важно для эффективного использования фикстур, управления зависимостями и оптимизации времени выполнения тестов.

Ключевые факторы, определяющие момент вызова

Время вызова фикстуры определяется двумя основными параметрами:

  1. Область видимости (scope): Определяет, как часто фикстура создается и разрушается.
  2. Запрос фикстуры тестом: Фикстура вызывается только тогда, когда тестовая функция явно запрашивает её в качестве аргумента.

Детальный разбор по областям видимости

1. scope="function" (значение по умолчанию)

Фикстура вызывается один раз для каждой тестовой функции, которая её запрашивает.

  • Когда вызывается: Непосредственно перед выполнением каждого теста, который имеет параметр с именем фикстуры.
  • Когда завершается: Сразу после завершения этого теста (если используется yield или addfinalizer).
  • Аналог: @BeforeEach / @AfterEach в JUnit.
import pytest

@pytest.fixture(scope="function")
def fresh_database():
    print("\nИнициализация БД для теста...")
    db = {"users": []}
    yield db  # Передача данных тесту
    print("\nОчистка БД после теста...")

def test_add_user(fresh_database):
    fresh_database["users"].append("Alice")
    assert len(fresh_database["users"]) == 1

def test_count_users(fresh_database):
    # Эта функция получит СВОЙ, новый экземпляр `fresh_database`
    assert len(fresh_database["users"]) == 0

Вывод:

Инициализация БД для теста...
Очистка БД после теста...
.Инициализация БД для теста...
Очистка БД после теста...
.

2. scope="class"

Фикстура вызывается один раз для всего тестового класса, независимо от количества методов в нём.

  • Когда вызывается: Один раз перед выполнением первого тестового метода в классе, который запрашивает фикстуру.
  • Когда завершается: После выполнения последнего тестового метода в этом классе.
import pytest

@pytest.fixture(scope="class")
def shared_config():
    print("\n>>> Загрузка конфигурации для класса")
    config = {"mode": "test", "timeout": 30}
    yield config
    print("\n<<< Выгрузка конфигурации для класса")

@pytest.mark.usefixtures("shared_config")
class TestAPI:
    def test_endpoint_a(self, shared_config):
        assert shared_config["mode"] == "test"

    def test_endpoint_b(self, shared_config):
        # Оба метода используют один и тот же объект `shared_config`
        assert shared_config["timeout"] == 30

Вывод: Фикстура shared_config будет инициализирована и завершена только один раз для всего TestAPI.

3. scope="module"

Фикстура вызывается один раз для всего модуля (файла с тестами).

  • Когда вызывается: Один раз при первом запросе фикстуры любым тестом в этом модуле.
  • Когда завершается: После выполнения всех тестов в модуле.
# test_module.py
import pytest
import expensive_calculations

@pytest.fixture(scope="module")
def heavy_computation_result():
    print("\n--- Выполнение дорогостоящих вычислений для модуля ---")
    result = expensive_calculations.compute() # Долгая операция
    yield result
    print("\n--- Освобождение ресурсов модуля ---")

def test_result_type(heavy_computation_result):
    assert isinstance(heavy_computation_result, dict)

def test_result_value(heavy_computation_result):
    # Оба теста используют результат одного вычисления
    assert heavy_computation_result["status"] == "ok"

4. scope="session"

Фикстура вызывается один раз за всю сессию выполнения тестов (т.е. за один запуск pytest).

  • Когда вызывается: Один раз в самом начале тестовой сессии, при первом запросе этой фикстуры любым тестом.
  • Когда завершается: В самом конце тестовой сессии, после выполнения всех тестов во всех модулях.
  • Типичное использование: Установка соединения с базой данных, запуск и остановка Selenium-сервера или веб-приложения для тестирования.
# conftest.py
import pytest

@pytest.fixture(scope="session")
def browser():
    from selenium import webdriver
    print("\n===== Запуск браузера для сессии =====")
    driver = webdriver.Chrome()
    driver.implicitly_wait(10)
    yield driver
    driver.quit()
    print("\n===== Закрытие браузера после сессии =====")

Все тесты во всех модулях проекта, которые запрашивают фикстуру browser, будут использовать один и тот же экземпляр браузера.

Важные особенности вызова

  • Автоматическое использование (autouse=True): Фикстура с этим параметром будет вызываться автоматически для всех тестов в её области видимости, без явного запроса в аргументах теста. Это влияет только на момент начала использования, но не отменяет правила области видимости.
  • Зависимости фикстур: Если фикстура A зависит от фикстуры B (указана в её параметрах), то B будет вызвана непосредственно перед вызовом A, с учётом своей области видимости.
  • Финальная логика (yield vs addfinalizer): Код после yield или зарегистрированный через request.addfinalizer() выполняется в момент завершения соответствующей области видимости (после теста, класса, модуля или сессии). Это гарантирует корректное освобождение ресурсов.

Практические рекомендации

  • Используйте scope="session" для дорогостоящих, но неизменяемых в течение прогона операций (логин, запуск сервиса).
  • Используйте scope="module" для подготовки данных, общих для всех тестов в одном файле.
  • scope="function" — ваш выбор по умолчанию для изоляции тестов друг от друга.
  • Старайтесь избегать autouse=True, если только фикстура не нужна абсолютно всем тестам в области. Явные зависимости улучшают читаемость.

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