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

Что такое Scope в PyTest?

1.3 Junior🔥 131 комментариев
#Теория тестирования

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

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

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

Что такое Scope в PyTest?

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

Основные уровни Scope и их поведение

PyTest предоставляет пять уровней scope, которые указываются через параметр scope при дефиниции фикстуры (@pytest.fixture(scope="...")):

  1. function (по умолчанию)
    *   Фикстура создается и разрушается для **каждого отдельного теста**.
    *   Идеально для **изоляции тестов**, чтобы состояние одного теста не влияло на другой.
    *   Пример: фикстура, которая генерирует уникальные данные для каждого теста.

```python
import pytest

@pytest.fixture(scope="function")
def fresh_user_data():
    # Генерирует новые данные перед каждым тестом
    return {"username": f"user_{uuid.uuid4()}", "email": f"test{uuid.uuid4()}@example.com"}

def test_user_creation(fresh_user_data):
    # Здесь fresh_user_data уникален для этого теста
    assert "username" in fresh_user_data
```

2. class

    *   Фикстура создается один раз для **каждого тестового класса** и разрушается после выполнения всех его методов.
    *   Полезно, когда несколько тестов в одном классе работают с одним общим ресурсом.
    *   Фикстура вызывается в методах класса через параметр или `request.cls`.

```python
import pytest

@pytest.fixture(scope="class")
def shared_db_connection():
    conn = create_db_connection()
    yield conn
    conn.close()

class TestUserSuite:
    def test_insert_user(self, shared_db_connection):
        # Все методы класса используют один connection
        shared_db_connection.execute("INSERT INTO users ...")

    def test_select_user(self, shared_db_connection):
        # Здесь connection тот же, что в test_insert_user
        result = shared_db_connection.execute("SELECT ...")
```

3. module

    *   Фикстура создается один раз для **каждого файла модуля** (`.py`) и разрушается после выполнения всех тестов в этом модуле.
    *   Эффективна для дорогостоящих операций, которые можно разделить между многими тестами одного модуля (например, запуск приложения, чтение конфигурационного файла).

```python
import pytest

@pytest.fixture(scope="module")
def app_instance():
    # Создание тяжелого объекта приложения один раз на модуль
    app = MyApplication(config="module_config.json")
    yield app
    app.shutdown()

# Все тесты в этом файле используют один app_instance
def test_app_endpoint_1(app_instance):
    response = app_instance.get("/api/v1/status")

def test_app_endpoint_2(app_instance):
    response = app_instance.post("/api/v1/data")
```

4. package (или session для более широкого контекста)

    *   Фикстура создается один раз для **каждой директории (пакета)**, содержащей тесты, и разрушается после выполнения всех тестов в этом пакете.
    *   Менее распространен, но полезен для ресурсов, специфичных для группы модулей.

  1. session (наиболее широкий)
    *   Фикстура создается **единственный раз** за всю сессию выполнения тестов (например, при запуске `pytest` для всей проектной директории) и разрушается после завершения **всех тестов**.
    *   Идеальный выбор для **глобальных, дорогостоящих ресурсов**, которые должны быть доступны всем тестам и не могут/не должны пересоздаваться (например, подключение к удаленной базе данных, запуск Docker контейнера, глобальная конфигурация).

```python
import pytest

@pytest.fixture(scope="session")
def global_docker_container():
    # Запуск контейнера один раз для всей сессии тестов
    container = docker_client.containers.run("my-test-db", detach=True)
    yield container
    container.stop()

# Тесты из разных модулей и пакетов используют один контейнер
def test_from_module_a(global_docker_container):
    # Проверка связи с контейнером
    pass

def test_from_module_b(global_docker_container):
    # Проверка другой функциональности с тем же контейнером
    pass
```

Автоматическое управление зависимостями (Automatic Dependency Management)

PyTest автоматически управляет порядком создания и разрушения фикстур на основе их scope и зависимостей. Фикстура с более широким scope (например, session) будет создана раньше и разрушена позже, чем фикстуры с более узким scope (например, function), которые зависят от нее. Это гарантирует корректную иерархию ресурсов.

import pytest

# Session fixture создается ПЕРВЫМ
@pytest.fixture(scope="session")
def heavy_session_resource():
    resource = start_heavy_resource()
    yield resource
    resource.stop()

# Module fixture создается ПОСЛЕ session, но раньше function
@pytest.fixture(scope="module")
def module_config(heavy_session_resource):  # Зависит от session fixture!
    config = load_config(heavy_session_resource)
    yield config

# Function fixture создается ПОСЛЕ module и разрушается перед ним
@pytest.fixture(scope="function")
def test_data(module_config):  # Зависит от module fixture!
    data = generate_data(module_config)
    yield data

Практические рекомендации по выбору Scope

  • Изоляция и безопасность: Если тесты могут изменять состояние ресурса и влиять друг на друга — используйте function или class.
  • Производительность: Если создание ресурса занимает много времени (подключение к БД, запуск сервера), и тесты его не изменяют — используйте module или session.
  • Чистота тестов: Фикстуры с широким scope часто используют yield (генераторы) для четкого разделения этапов setup и teardown.
  • Контекст зависимости: Фикстура может зависеть от другой фикстуры только если ее scope равен или шире. Фикстура function может зависеть от module, но фикстура session не может зависеть от function.

Понимание и правильное применение scope позволяет строить гибкую, эффективную и надежную инфраструктуру тестов, балансируя между изоляцией, производительностью и управлением ресурсами.