Fixtures are pytest's central idea: they replace setUp methods with composable, explicit dependencies.
A fixture is a function decorated with @pytest.fixture that prepares something a test needs: an object, a temporary file, a database session. A test asks for it simply by having a parameter with the fixture's name. pytest calls the fixture, passes its return value, and the test uses it.
Why this is better than shared setup methods:
- Each test declares exactly what it depends on, visible in its signature.
- Fixtures can use other fixtures the same way, building small layers: a
userfixture can depend on adbfixture. - Each test gets a fresh value by default (function scope), so tests don't leak state into each other.
- The same fixture is reused across many tests and files.
A fixture runs only when some test requests it. If several fixtures in one test's dependency graph request the same fixture, it's created once for that test and shared.
Name fixtures for what they provide (client, admin_user, sample_order), not for the action (setup_stuff). Keep them small and compose them, rather than building one giant fixture that sets up the world.
When a fixture needs cleanup, it uses yield instead of return, covered in the next practical lesson.
Example
# test_orders.py
import pytest
class Order:
def __init__(self, customer):
self.customer, self.items = customer, []
def add(self, name, price):
self.items.append((name, price))
def total(self):
return sum(p for _, p in self.items)
@pytest.fixture
def customer():
return {"name": "Ada", "vip": True}
@pytest.fixture
def order(customer): # fixtures can use fixtures
o = Order(customer)
o.add("book", 12)
return o
def test_total(order):
assert order.total() == 12
def test_fresh_order_each_test(order):
order.add("pen", 3)
assert order.total() == 15 # not affected by other testsRemember
- @pytest.fixture defines setup; tests request it by parameter name
- Fixtures can depend on other fixtures
- Default scope is per test: each test gets a fresh value
- Fixtures run only when requested
Watch out for
- Calling a fixture function directly from a test instead of requesting it as an argument (pytest raises an error).