What Are Fixtures?
Fixtures are pytest's answer to setup and teardown. They provide a clean, modular way to prepare test data, set up resources, and clean up after tests finish. Instead of repeating setup code in every test, you define it once in a fixture.
Basic Fixture
A fixture is a function decorated with @pytest.fixture. It can set up data, create objects, or establish connections:
import pytest
@pytest.fixture
def sample_user():
return {
"name": "Alice",
"email": "alice@example.com",
"age": 30
}
def test_user_name(sample_user):
assert sample_user["name"] == "Alice"
def test_user_email(sample_user):
assert sample_user["email"] == "alice@example.com"
pytest automatically detects that sample_user is a fixture and passes the fixture's return value to the test function.
Why Fixtures Are Better Than Setup
Compare these approaches:
# Without fixtures - repetitive setup
def get_user():
return {"name": "Alice", "email": "alice@example.com"}
def test_user_name():
user = get_user()
assert user["name"] == "Alice"
def test_user_email():
user = get_user() # duplicated!
assert user["email"] == "alice@example.com"
# With fixtures - clean and DRY
@pytest.fixture
def user():
return {"name": "Alice", "email": "alice@example.com"}
def test_user_name(user):
assert user["name"] == "Alice"
def test_user_email(user):
assert user["email"] == "alice@example.com"
Fixture Naming
Fixture names are the parameter names of your test functions. pytest matches them automatically:
@pytest.fixture
def database_connection():
conn = create_connection()
yield conn
conn.close()
# The parameter name MUST match the fixture name
def test_query(database_connection):
result = database_connection.execute("SELECT 1")
assert result is not None