Databases, servers and temp resources need reliable cleanup and shouldn't be recreated for every single test.
A fixture that needs cleanup uses `yield`: code before yield is setup, the yielded value goes to the test, and code after yield is teardown. Teardown runs whether the test passed or failed. If setup raises before the yield, teardown doesn't run, so acquire resources in an order that keeps that safe. Using a with block around the yield is a neat way to reuse existing context managers.
Scope controls how often a fixture is created:
function(default): once per test.class,module,package: once per class, file or package.session: once for the whole run.
Use broader scopes for expensive, effectively read-only resources: starting a database container, loading a big model, creating an app instance. Then combine them with narrow-scoped fixtures for the mutable part, for example a session-scoped database engine and a function-scoped transaction that's rolled back after each test.
The rule: a fixture can only depend on fixtures of the same or broader scope. A session fixture can't use a function fixture (pytest reports a ScopeMismatch).
Teardown order is the reverse of setup, so dependent resources are torn down before what they depend on. For complex cleanup, request.addfinalizer(fn) registers additional teardown callbacks.
Example
# test_scope.py
import pytest
log = []
@pytest.fixture(scope="module")
def database():
log.append("connect") # expensive: once per module
yield {"rows": []}
log.append("disconnect")
@pytest.fixture
def transaction(database):
log.append("begin")
yield database
database["rows"].clear() # rollback after every test
log.append("rollback")
def test_insert(transaction):
transaction["rows"].append(1)
assert transaction["rows"] == [1]
def test_isolated(transaction):
assert transaction["rows"] == []
assert log == ["connect", "begin", "rollback", "begin"]Remember
- yield splits a fixture into setup and teardown
- Teardown runs even when the test fails
- Scopes: function, class, module, package, session
- Fixtures may only depend on same or broader scope
Watch out for
- Making a mutable fixture session-scoped, so one test's changes leak into others.