Fixtures
The fixture is the test's dependency: the @pytest.fixture marks the function whose return (or yield) is the setup, and the test requests it by the parameter name - the no import, the no global, the setup runs once per the requested test (the function scope the default). The fixture is the unittest's setUp/tearDown generalized: the yield is the setup/teardown pair (the before the yield, the after), the value is the return or the yield, and the scope (the next chapter) controls how often it runs. This chapter covers the fixture definition (the plain return, the yield), the request (the parameter name, the request object), the fixture as the replacement for the conftest global, and the fixture the test does not use (the no cost, the no run).
The Fixture: The Return and the Yield
# the PLAIN fixture: the return (the the value, the
# the no teardown, the the once per test)
import pytest
@pytest.fixture
def sample_text():
return "the quick brown fox jumps over the lazy dog"
# the test REQUESTS by the name (the the parameter,
# the the no import, the the conftest the the shared)
def test_word(sample_text):
from texttools import word_count
assert word_count(sample_text) == 9
# the YIELD fixture: the the setup -> the yield -> the
# the teardown (the resource the
# the open/close, the file the
# the create/delete)
@pytest.fixture
def tmp_word_file(tmp_path):
p = tmp_path / "words.txt"
p.write_text("one\ntwo\nthree\n")
yield p # the the value the the test
p.unlink() # the the teardown (the after)
def test_read(tmp_word_file):
assert tmp_word_file.read_text().splitlines() == [
"one", "two", "three"]
# the unlink RUNS after the test (the
# the pass or the fail, the
# the teardown the guaranteed)
The fixture is the @pytest.fixture-decorated function, and the test requests it by the parameter name - the def test_word(sample_text) receives the fixture's value, the no import of the fixture, the no global state. The plain fixture returns (the value, the no teardown - the immutable sample data), and the yield fixture is the setup/teardown pair: the code before the yield runs before the test, the yield value is the test's, and the code after runs after (the tmp_word_file creates the file, yields the path, unlinks it - the teardown on the pass AND the fail). The fixture is declared in the test file (the local) or the conftest.py (the shared, the every test below the directory), and the unused fixture does not run (the the request is the trigger - the declared-but-not-requested fixture costs nothing). The pattern is the one: the repeated setup is the fixture, the test is the assertion on the fixture's value, and the next chapter's scope and the dependency graph scale the same pattern to the session and the fixture-on-fixture.
The request Object
# the the request: the the fixture's CONTEXT (the the
# the node the fixture the serves,
# the the scope, the the params, the caller)
import pytest
@pytest.fixture
def labeled_sample(request):
# the the request.node: the test the the
# the fixture the serves (the
# the name, the file, the params)
name = request.node.name
return f"[{name}] the quick brown fox"
def test_labeled(labeled_sample):
assert labeled_sample.startswith("[test_labeled]")
# the params (the chapter 8, the the
# the the request.param the value):
# the fixture the per-test the the
# the different the input
The request fixture is the context: the request.node is the test item the fixture serves (the name, the file, the params), the request.scope is the scope the fixture runs at (the function, the module, the session), and the request.param is the value the parametrized fixture receives (the parametrization chapter). The use is the fixture that needs to know its caller (the labeled_sample prefixes the test name, the the report the per-test trace), and the rule is the keep it to the context the assertion cannot express - the plain value is the return, the request the metadata. The fixture-on-fixture (the labeled_sample could request another fixture, the dependency graph) and the conftest placement (the shared the conftest, the local the test file) are the two extensions, and the next chapter's scope is the third: how often the declared fixture runs, from the per-test function to the once-per-session.
The Working Rules
- The
@pytest.fixtureis the declared setup, the parameter name is the request. The no import, the no global - the test receives the fixture by the name, and the declared-but-not-requested fixture does not run (the request is the trigger). - The
yieldis the setup/teardown pair. The before theyieldthe setup, the value the test's, the after the teardown on the pass AND the fail - the resource (the file, the connection, the server) is theyield, the immutable sample the plain return. - The
conftest.pyis the shared, the test file the local. The fixture in thetests/conftest.pyreaches every test below the directory, the test-file fixture the one feature's - the placement is the visibility, and the name collision the closer scope wins. - The
requestis the context, therequest.paramthe parametrized value. Therequest.nodethe caller (the name, the file), therequest.scopethe scope, therequest.paramthe per-test input (the parametrization chapter) - the metadata the assertion cannot express.
Summary
The fixture is the test's dependency: the @pytest.fixture function the test requests by the parameter name (the no import, the no global), the plain return the immutable value, and the yield the setup/teardown pair (the before the setup, the value the test's, the after the teardown on the pass and the fail - the file, the connection, the server). The declared-but-not-requested fixture does not run, the conftest.py fixture is shared to every test below the directory (the test-file fixture the local), and the request object is the context (the request.node the caller, the request.scope the scope, the request.param the parametrized value). The pattern is the one the unittest's setUp/tearDown is replaced by: the repeated setup is the fixture, the test is the assertion on the fixture's value, and the next chapter's scope (the function to the session) plus the fixture-on-fixture dependency graph scale the same declaration to the whole suite.