Практическая ситуация: фикстура должна выполниться для теста, но её результат не нужен в теле теста. Как pytest подключит её в этом примере?
import pytest
@pytest.fixture
def audit_log():
print("setup")
yield
print("teardown")
@pytest.mark.usefixtures("audit_log")
def test_report():
assert True
Маркер pytest.mark.usefixtures("audit_log") заставит pytest выполнить фикстуру audit_log для test_report, хотя имя фикстуры отсутствует в аргументах теста. Сначала выполнится код до yield, затем тест, а после теста — код после yield.
Маркер подключает фикстуру к тесту, но не передаёт её возвращаемое значение в функцию теста.
В тестах часто требуется выполнить подготовку или очистку, но сам тест не использует созданный объект напрямую. Например, тесту может быть нужна регистрация временных данных, настройка окружения или очистка внешнего ресурса.
Если добавлять такую фикстуру в аргументы каждого теста, сигнатуры становятся искусственно перегруженными. usefixtures отделяет факт выполнения подготовительных действий от передачи значения в тест.
Фикстура, имя которой не указано в аргументах теста, обычно не становится его зависимостью автоматически. Поэтому простое объявление audit_log рядом с тестом не приведёт к её запуску.
Неверное решение может оставить тест без обязательной подготовки или очистки. Обратная проблема тоже возможна: использование usefixtures там, где тесту нужен объект фикстуры, приведёт к невозможности обратиться к этому объекту через локальную переменную.
При сборке теста pytest видит маркер usefixtures и добавляет указанное имя в набор зависимостей теста. Затем pytest разрешает фикстуру обычным способом: ищет её в тестовом модуле, подходящем conftest.py или другом зарегистрированном месте.
Для приведённого примера порядок такой:
print("setup");yield;test_report;print("teardown").Значение, переданное через yield, при usefixtures не появляется в аргументах теста. Если объект нужен в теле теста, фикстуру следует указать явно:
usefixtures можно применять к отдельному тесту, классу или модулю. Область действия и кэширование фикстуры по-прежнему определяются её scope; сам маркер не меняет жизненный цикл.
По смыслу usefixtures подходит для побочных эффектов: настройки, создания записей, очистки или проверки состояния окружения. Для данных, которыми тест должен пользоваться, предпочтительнее явная зависимость в аргументах: она делает контракт теста видимым и упрощает анализ зависимостей.
В интеграционных тестах перед каждым тестом нужно включать режим аудита, а после него удалять созданный журнал. Тесты не обращаются к объекту фикстуры, поэтому добавление аргумента audit_log в десятки функций не несёт полезной информации.
Рассматривались три варианта. Явная передача фикстуры хорошо показывает зависимость, но перегружает сигнатуры неиспользуемым параметром. Autouse-фикстура не требует маркеров, но может неожиданно влиять на тесты в области действия и усложнять понимание причин замедления. usefixtures явно показывает, какие тесты требуют подготовки, не добавляя лишний аргумент.
Выбран usefixtures на уровне тестового класса для интеграционного набора. В результате подготовка и очистка выполняются гарантированно, а тестовые функции остаются компактными; при этом зависимость видна непосредственно на уровне класса.
Чем usefixtures отличается от передачи фикстуры аргументом?
При передаче имени в аргументах pytest не только запускает фикстуру, но и передаёт её результат тесту. usefixtures запускает фикстуру без инъекции результата. Поэтому выбирать нужно по потребности теста: нужен объект — аргумент, нужен только побочный эффект — usefixtures.
Что произойдёт, если имя в usefixtures указано с ошибкой?
Тест не сможет получить требуемую фикстуру, и pytest завершит его с ошибкой разрешения фикстуры, обычно указывая неизвестное имя. Это отличается от ситуации, когда фикстура просто не используется: имя в маркере является явной зависимостью и проверяется pytest.
Меняет ли usefixtures область действия фикстуры?
Нет. usefixtures только добавляет зависимость к тесту или группе тестов. Если фикстура имеет scope="module", один экземпляр будет обслуживать тесты модуля; если scope="function", она будет создаваться для каждого теста. Маркер не превращает function-scoped фикстуру в общую и не меняет правила совместимости областей действия.