Справочник по фикстурам
См. также
См. также
Встроенные фикстуры
Фикстуры определяются с помощью декоратора @pytest.fixture. В pytest есть несколько полезных встроенных фикстур:
-
capfd -
Перехватывает вывод в текстовом виде в файловые дескрипторы
1и2. -
capfdbinary -
Перехватывает вывод в виде байтов в файловые дескрипторы
1и2. -
caplog -
Управляет журналированием и предоставляет доступ к записям журнала.
-
capsys -
Перехватывает вывод в текстовом виде в
sys.stdoutиsys.stderr. -
capteesys -
Перехватывает вывод так же, как
capsys, но также передаёт текст дальше в соответствии с--capture. -
capsysbinary -
Перехватывает вывод в виде байтов в
sys.stdoutиsys.stderr. -
cache -
Сохраняет значения между запусками pytest и извлекает их.
-
doctest_namespace -
Предоставляет словарь, добавляемый в пространство имён doctest.
-
monkeypatch -
Временно изменяет классы, функции, словари,
os.environи другие объекты. -
pytestconfig -
Предоставляет доступ к значениям конфигурации, менеджеру плагинов и хукам плагинов.
-
subtests -
Позволяет объявлять под-тесты внутри тестовых функций.
-
record_property -
Добавляет дополнительные свойства к тесту.
-
record_testsuite_property -
Добавляет дополнительные свойства к набору тестов.
-
recwarn -
Записывает предупреждения, выданные тестовыми функциями.
-
request -
Предоставляет информацию о выполняемой тестовой функции.
-
testdir -
Предоставляет временный каталог для запуска и тестирования плагинов pytest.
-
tmp_path -
Предоставляет объект
pathlib.Path, указывающий на временный каталог, уникальный для каждой тестовой функции. -
tmp_path_factory -
Создаёт временные каталоги на время сессии и возвращает объекты
pathlib.Path. -
tmpdir -
Предоставляет объект py.path.local, указывающий на временный каталог, уникальный для каждой тестовой функции; заменён на
tmp_path. -
tmpdir_factory -
Создаёт временные каталоги на время сессии и возвращает объекты
py.path.local; заменён наtmp_path_factory.
Доступность фикстур
Доступность фикстуры определяется с точки зрения теста. Тест может запросить фикстуру, только если он находится в области действия, в которой эта фикстура определена. Если фикстура определена внутри класса, её могут запрашивать только тесты внутри этого класса. Но если фикстура определена в глобальной области видимости модуля, её может запросить каждый тест в этом модуле, даже если он определён внутри класса.
Аналогично, автоприменяемая фикстура может повлиять на тест, только если этот тест находится в той же области действия, в которой определена эта автоприменяемая фикстура (см. раздел Автоприменяемые фикстуры выполняются первыми в своей области действия).
Фикстура также может запрашивать любую другую фикстуру, независимо от места её определения, если тест, запрашивающий их, имеет доступ ко всем задействованным фикстурам.
Например, вот файл с тестами, в котором фикстура (outer) запрашивает фикстуру (inner) из области действия, в которой она не была определена:
from __future__ import annotations
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def outer(order, inner):
order.append("outer")
class TestOne:
@pytest.fixture
def inner(self, order):
order.append("one")
def test_order(self, order, outer):
assert order == ["one", "outer"]
class TestTwo:
@pytest.fixture
def inner(self, order):
order.append("two")
def test_order(self, order, outer):
assert order == ["two", "outer"]
С точки зрения тестов, все необходимые им фикстуры доступны:
Поэтому при запуске у outer не возникнет проблем с поиском inner, поскольку pytest выполнял поиск с точки зрения тестов.
Примечание
Область действия, в которой определена фикстура, не влияет на порядок её создания: этот порядок определяется логикой, описанной здесь.
conftest.py: совместное использование фикстур в нескольких файлах
Файл conftest.py служит для предоставления фикстур всему каталогу. Фикстуры, определённые в conftest.py, могут использоваться любым тестом в этом пакете без необходимости их импорта (pytest обнаружит их автоматически).
Можно создавать несколько вложенных каталогов/пакетов с тестами, и в каждом каталоге может быть свой файл conftest.py со своими фикстурами, дополняющими фикстуры, предоставляемые файлами conftest.py в родительских каталогах.
Например, для следующей структуры файлов тестов:
tests/
__init__.py
conftest.py
# content of tests/conftest.py
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def top(order, innermost):
order.append("top")
test_top.py
# content of tests/test_top.py
import pytest
@pytest.fixture
def innermost(order):
order.append("innermost top")
def test_order(order, top):
assert order == ["innermost top", "top"]
subpackage/
__init__.py
conftest.py
# content of tests/subpackage/conftest.py
import pytest
@pytest.fixture
def mid(order):
order.append("mid subpackage")
test_subpackage.py
# content of tests/subpackage/test_subpackage.py
import pytest
@pytest.fixture
def innermost(order, mid):
order.append("innermost subpackage")
def test_order(order, top):
assert order == ["mid subpackage", "innermost subpackage", "top"]
Границы областей действия можно представить так:
Каталоги становятся своего рода областями действия: фикстуры, определённые в файле conftest.py в конкретном каталоге, становятся доступными во всей этой области.
Тесты могут искать фикстуры вверх по иерархии (выходя за пределы круга), но не могут идти вниз (внутрь круга), продолжая поиск. Поэтому tests/subpackage/test_subpackage.py::test_order сможет найти фикстуру innermost, определённую в tests/subpackage/test_subpackage.py, но фикстура, определённая в tests/test_top.py, будет ему недоступна, поскольку для её поиска пришлось бы перейти на уровень ниже (внутрь круга).
Будет использована первая найденная тестом фикстура, поэтому фикстуры можно переопределять, если нужно изменить или расширить её поведение для определённой области действия.
Файл conftest.py также можно использовать для реализации локальных плагинов для отдельных каталогов.
Фикстуры из сторонних плагинов
Фикстуры не обязательно должны быть определены в этой структуре, чтобы быть доступными тестам. Их также могут предоставлять установленные сторонние плагины — так работает множество плагинов pytest. Если такие плагины установлены, предоставляемые ими фикстуры можно запрашивать из любой части набора тестов.
Поскольку сторонние плагины предоставляют фикстуры извне структуры набора тестов, они не создают область действия, подобную той, которую задают файлы conftest.py и каталоги набора тестов. Поэтому pytest будет искать фикстуры, переходя между областями действия, как описано выше, и обращаться к фикстурам из плагинов только в последнюю очередь.
Например, для следующей структуры файлов:
tests/
__init__.py
conftest.py
# content of tests/conftest.py
import pytest
@pytest.fixture
def order():
return []
subpackage/
__init__.py
conftest.py
# content of tests/subpackage/conftest.py
import pytest
@pytest.fixture(autouse=True)
def mid(order, b_fix):
order.append("mid subpackage")
test_subpackage.py
# content of tests/subpackage/test_subpackage.py
import pytest
@pytest.fixture
def inner(order, mid, a_fix):
order.append("inner subpackage")
def test_order(order, inner):
assert order == ["b_fix", "mid subpackage", "a_fix", "inner subpackage"]
Если установлен plugin_a, предоставляющий фикстуру a_fix, и установлен plugin_b, предоставляющий фикстуру b_fix, поиск фикстур тестом будет выглядеть так:
pytest будет искать a_fix и b_fix в плагинах только после того, как сначала выполнит поиск в областях действия внутри tests/.
Примечание
pytest может сообщить, какие фикстуры доступны для заданного теста. Для этого вызовите pytest, указав имя теста (или его область действия), и передайте флаг --fixtures, например pytest --fixtures test_something.py (фикстуры с именами, начинающимися с _, будут показаны только при передаче флага -v).
Порядок создания фикстур
Когда pytest собирается выполнить тест и уже знает, какие фикстуры будут задействованы, ему нужно определить порядок их выполнения. Для этого учитываются три фактора:
- область действия
- зависимости
- автоприменение
Имена фикстур или тестов, место и порядок их определения, а также порядок запроса фикстур не влияют на порядок выполнения — если только это не совпадение. Хотя pytest старается обеспечивать постоянство таких совпадений от запуска к запуску, полагаться на них не следует. Если необходимо управлять порядком, безопаснее всего опираться на эти три фактора и явно задавать зависимости.
Сначала выполняются фикстуры с более широкой областью действия
При запросе фикстур для функции фикстуры с более широкой областью действия (например, session) выполняются раньше фикстур с более узкой областью действия (например, function или class).
Вот пример:
from __future__ import annotations
import pytest
@pytest.fixture(scope="session")
def order():
return []
@pytest.fixture
def func(order):
order.append("function")
@pytest.fixture(scope="class")
def cls(order):
order.append("class")
@pytest.fixture(scope="module")
def mod(order):
order.append("module")
@pytest.fixture(scope="package")
def pack(order):
order.append("package")
@pytest.fixture(scope="session")
def sess(order):
order.append("session")
class TestClass:
def test_order(self, func, cls, mod, pack, sess, order):
assert order == ["session", "package", "module", "class", "function"]
Тест пройдёт, потому что фикстуры с более широкой областью действия выполняются первыми.
Порядок будет таким:
Фикстуры с одинаковой областью действия выполняются с учётом зависимостей
Если фикстура запрашивает другую фикстуру, сначала выполняется запрошенная фикстура. Поэтому, если фикстура a запрашивает фикстуру b, сначала выполнится фикстура b, поскольку a зависит от b и не может работать без неё. Даже если a не нужен результат b, она всё равно может запросить b, если требуется обеспечить её выполнение после b.
Например:
from __future__ import annotations
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def a(order):
order.append("a")
@pytest.fixture
def b(a, order):
order.append("b")
@pytest.fixture
def c(b, order):
order.append("c")
@pytest.fixture
def d(c, b, order):
order.append("d")
@pytest.fixture
def e(d, b, order):
order.append("e")
@pytest.fixture
def f(e, order):
order.append("f")
@pytest.fixture
def g(f, c, order):
order.append("g")
def test_order(g, order):
assert order == ["a", "b", "c", "d", "e", "f", "g"]
Если изобразить зависимости, получится примерно такая схема:
Правила, задаваемые каждой фикстурой (то есть то, после каких фикстур она должна выполняться), достаточно полны, чтобы свести схему к следующей линейной последовательности:
Эти запросы должны предоставлять достаточно информации, чтобы pytest мог определить чёткую линейную цепочку зависимостей, а значит, и порядок действий для заданного теста. При наличии неоднозначности, когда порядок действий можно интерпретировать несколькими способами, следует исходить из того, что pytest в любой момент может выбрать любую из таких интерпретаций.
Например, если d не запрашивала бы c, то граф выглядел бы так:
Поскольку c запрашивала только g, а g также запрашивает f, теперь неясно, должна ли c выполняться до или после f, e или d. Для c установлены только два правила: она должна выполняться после b и до g.
pytest не знает, куда поместить c в этом случае, поэтому следует исходить из того, что она может находиться в любом месте между g и b.
Это не обязательно плохо, но об этом следует помнить. Если порядок выполнения может повлиять на поведение, которое проверяет тест, или иным образом изменить его результат, порядок нужно задать явно так, чтобы pytest мог выстроить его в линейную последовательность.
Автоприменяемые фикстуры выполняются первыми в своей области действия
Считается, что автоприменяемые фикстуры относятся ко всем тестам, которые могут на них ссылаться, поэтому в своей области действия они выполняются раньше других фикстур. Фикстуры, запрашиваемые автоприменяемыми фикстурами, фактически также становятся автоприменяемыми для тех тестов, к которым относится исходная автоприменяемая фикстура.
Поэтому, если фикстура a является автоприменяемой, а фикстура b — нет, но фикстура a запрашивает фикстуру b, то фикстура b фактически тоже станет автоприменяемой, но только для тестов, к которым относится a.
В предыдущем примере граф становился неоднозначным, если d не запрашивала c. Но если бы c была автоприменяемой, то b и a фактически тоже стали бы автоприменяемыми, поскольку от них зависит c. В результате все они переместились бы выше фикстур, не являющихся автоприменяемыми, в пределах этой области действия.
Поэтому, если бы файл с тестами выглядел так:
from __future__ import annotations
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def a(order):
order.append("a")
@pytest.fixture
def b(a, order):
order.append("b")
@pytest.fixture(autouse=True)
def c(b, order):
order.append("c")
@pytest.fixture
def d(b, order):
order.append("d")
@pytest.fixture
def e(d, order):
order.append("e")
@pytest.fixture
def f(e, order):
order.append("f")
@pytest.fixture
def g(f, c, order):
order.append("g")
def test_order_and_g(g, order):
assert order == ["a", "b", "c", "d", "e", "f", "g"]
граф выглядел бы так:
Теперь c можно разместить в графе выше d, поэтому pytest снова может выстроить граф в линейную последовательность:
В этом примере c фактически делает b и a автоприменяемыми фикстурами.
Однако будьте осторожны с автоприменением: автоприменяемая фикстура будет запускаться автоматически для каждого теста, до которого она может дойти, даже если тест её не запрашивает. Например, рассмотрим следующий файл:
from __future__ import annotations
import pytest
@pytest.fixture(scope="class")
def order():
return []
@pytest.fixture(scope="class", autouse=True)
def c1(order):
order.append("c1")
@pytest.fixture(scope="class")
def c2(order):
order.append("c2")
@pytest.fixture(scope="class")
def c3(order, c1):
order.append("c3")
class TestClassWithC1Request:
def test_order(self, order, c1, c3):
assert order == ["c1", "c3"]
class TestClassWithoutC1Request:
def test_order(self, order, c2):
assert order == ["c1", "c2"]
Хотя ничто в TestClassWithoutC1Request не запрашивает c1, она всё равно выполняется для содержащихся в нём тестов:
Однако сам факт того, что одна автоприменяемая фикстура запросила фикстуру, не являющуюся автоприменяемой, не означает, что последняя становится автоприменяемой во всех областях, к которым она может относиться. Фактически она становится автоприменяемой только в тех областях, к которым относится настоящая автоприменяемая фикстура (запросившая фикстуру, не являющуюся автоприменяемой).
Например, рассмотрим следующий файл с тестами:
from __future__ import annotations
import pytest
@pytest.fixture
def order():
return []
@pytest.fixture
def c1(order):
order.append("c1")
@pytest.fixture
def c2(order):
order.append("c2")
class TestClassWithAutouse:
@pytest.fixture(autouse=True)
def c3(self, order, c2):
order.append("c3")
def test_req(self, order, c1):
assert order == ["c2", "c3", "c1"]
def test_no_req(self, order):
assert order == ["c2", "c3"]
class TestClassWithoutAutouse:
def test_req(self, order, c1):
assert order == ["c1"]
def test_no_req(self, order):
assert order == []
Его структура будет примерно такой:
Для test_req и test_no_req внутри TestClassWithAutouse фикстура c3 фактически делает c2 автоприменяемой фикстурой. Поэтому c2 и c3 выполняются для обоих тестов, несмотря на то, что их не запрашивали; также для test_req c2 и c3 выполняются до c1.
Если бы это сделало c2 действительно автоприменяемой фикстурой, то c2 также выполнялась бы для тестов внутри TestClassWithoutAutouse, поскольку при необходимости они могут обращаться к c2. Но этого не происходит: с точки зрения тестов TestClassWithoutAutouse, c2 не является автоприменяемой фикстурой, поскольку им недоступна c3.
Примечание
pytest может сообщить, в каком порядке будут выполняться фикстуры для заданного теста. Для этого вызовите pytest, указав имя теста (или его область действия), и передайте флаг --setup-plan, например pytest --setup-plan test_something.py (фикстуры с именами, начинающимися с _, будут показаны только при передаче флага -v).
© 2015–2026 Holger Krekel and pytest-dev team
Licensed under the MIT License.
https://docs.pytest.org/en/stable/reference/fixtures.html