Skip to main content

Fixtures & Conftest

Fixtures are pytest's dependency injection system. Instead of copying setup/teardown code into every test, you declare what a test needs and pytest injects it automatically.

Basic Fixture

import pytest

@pytest.fixture
def sample_user():
    return {"name": "Alice", "email": "alice@example.com", "role": "admin"}

def test_user_name(sample_user):
    assert sample_user["name"] == "Alice"

def test_user_role(sample_user):
    assert sample_user["role"] == "admin"

The fixture function name becomes the parameter name in the test — pytest matches them automatically.

Setup and Teardown with yield

import pytest

@pytest.fixture
def db_connection():
    conn = create_db_connection()   # setup
    yield conn                       # test runs here
    conn.close()                     # teardown (always runs)

Code before yield is setup; code after is teardown. The teardown runs even if the test fails.

Fixture Scope

@pytest.fixture(scope="function")   # default  new instance per test
@pytest.fixture(scope="class")      # one instance per test class
@pytest.fixture(scope="module")     # one instance per test file
@pytest.fixture(scope="session")    # one instance for the whole test run

Use session scope for expensive resources like database connections or browser drivers.

conftest.py

Fixtures in conftest.py are automatically available to all tests in the same directory and below — no import needed.

tests/
├── conftest.py           fixtures available everywhere
├── test_auth.py
├── api/
   ├── conftest.py       fixtures available to api/ tests only
   └── test_users.py
└── ui/
    └── test_homepage.py
# tests/conftest.py
import pytest
from myapp import create_app, db

@pytest.fixture(scope="session")
def app():
    app = create_app(testing=True)
    with app.app_context():
        db.create_all()
        yield app
        db.drop_all()

@pytest.fixture
def client(app):
    return app.test_client()        # fixtures can use other fixtures

Fixture Dependency Graph

Fixture dependency chain
Ctrl+Enter
HTML
CSS
JS
Preview

Parametrised Fixtures

@pytest.fixture(params=["sqlite", "postgresql"])
def database(request):
    return connect(request.param)

def test_insert(database):
    # runs twice  once for sqlite, once for postgresql
    assert database.insert({"key": "val"}) == 1

pytest creates a separate test case for each param value automatically.