← Назад к списку
ТехническаяPythonMiddle

Как устроены фикстуры в pytest и как вы подходите к мокам и параметризации?

Короткий ответ

  • Фикстура — функция с @pytest.fixture, внедряется по имени аргумента
  • Scope управляет временем жизни: function, module, session
  • yield в фикстуре даёт setup и teardown в одном месте
  • conftest.py делает фикстуры доступными без импорта
  • parametrize запускает тест на наборе данных
  • Мокать лучше границы системы: сеть, время, БД

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

Как сказать вслух

пример ответа

Фикстура в pytest — это функция, которая готовит данные или окружение, а тест получает её просто по имени аргумента. Через yield в ней же описывается очистка, а scope управляет, создаётся она на каждый тест или один раз на сессию — так делают, например, подключение к базе. Параметризация позволяет прогнать один тест на таблице случаев. Мокаю я в основном внешние границы — HTTP, время, очереди, а не внутренности своего кода, иначе тесты проверяют моки, а не логику.

Подробный ответ

Основной ответ

pytest внедряет фикстуры по именам параметров теста: функция с @pytest.fixture вызывается автоматически, её результат попадает в тест. Фикстуры могут зависеть друг от друга и образуют граф. Код после yield выполняется как teardown даже при падении теста. Scope (function по умолчанию, class, module, session) контролирует переиспользование: дорогие ресурсы — контейнер с БД, клиент приложения — поднимают один раз на сессию. conftest.py публикует фикстуры на каталог без импортов. @pytest.mark.parametrize генерирует отдельный тест на каждый набор аргументов. Для моков используют monkeypatch или unittest.mock/pytest-mock; правило — подменять границы (HTTP-клиенты, часы, файловую систему), а наружный контракт проверять интеграционными тестами.

Ключевые моменты

  • Внедрение по имени. Тест объявляет нужное окружение аргументами — зависимости явные, дублирования setUp нет.
  • Scope и стоимость. session-фикстуры экономят минуты на дорогой инициализации, но требуют осторожности с общим состоянием.
  • Параметризация. Таблица «вход — ожидание» в одном декораторе; каждый случай отображается отдельным тестом в отчёте.
  • Дисциплина моков. Мокаем то, чем не управляем (сеть, время, сторонние API); перемоканный тест перестаёт ловить реальные баги.

Практический контекст

В реальных проектах встречаются фикстуры клиента FastAPI/Django, тестовой БД в транзакции с откатом, фабрики данных (factory_boy). Интервьюер спрашивает про scope и teardown, просит спроектировать тест для функции с HTTP-вызовом — и смотрит, что именно кандидат замокает. Красный флаг для него — моки внутренних функций собственного модуля.

Пример кода

import pytest

@pytest.fixture
def db():
    conn = create_test_db()
    yield conn
    conn.close()  # teardown выполнится даже при падении теста

@pytest.mark.parametrize("raw,expected", [
    ("  Hi ", "hi"),
    ("ABC", "abc"),
    ("", ""),
])
def test_normalize(raw, expected):
    assert normalize(raw) == expected

Частые ошибки

  • Делают изменяемую session-фикстуру и получают зависящие друг от друга тесты
  • Мокают внутренние функции своего кода вместо внешних границ
  • Патчат объект не в том модуле: нужно патчить там, где имя используется, а не где определено

ИП Кочкин Алексей Сергеевич · ИНН 390509026279 · ОГРНИП 325390000030973 · jiniys2005@yandex.ru