Skip to content
intermediate Phase 16 · Python Testing Advanced

Advanced pytest Fixtures

Master fixture scoping, parametrization, and fixture composition.

1h
0 problems
Topic Progress 0%

Fixture Fundamentals

Fixture Fundamentals

A fixture is a named setup function that tests request by parameter name:

# conftest.py — discovered automatically by pytest
import pytest

@pytest.fixture
def db(tmp_path):
    conn = connect(tmp_path / "test.db")
    yield conn          # everything after yield is teardown
    conn.close()

def test_insert(db):
    db.execute("INSERT INTO t VALUES (1)")
    assert db.fetch_one() == (1,)

Because db lives in conftest.py, every test in the directory tree gets it without imports. Teardown runs even when the test fails, mirroring try/finally. Fixtures compose: a fixture can request other fixtures by name, building layered setup (app → client → authed_client) without copy-paste.

Scopes and Parametrization

Scopes and Parametrization

Scopes control reuse: function (default, fresh per test), class, module, package, session (one per run).

@pytest.fixture(scope="session")
def live_api():
    with TestClient(app) as c:   # expensive: build once for the whole session
        yield c

@pytest.mark.parametrize("n,expected", [(0, 1), (1, 1), (5, 120)])
def test_factorial(n, expected):
    assert factorial(n) == expected

@pytest.fixture(params=[3338, 4450])
def port(request):
    return request.param          # fixture runs once per param

The scope rule: a fixture may only request fixtures of the same or broader scope. A session-scoped fixture asking for a function-scoped one errors at collection — setup order must be session → module → function, never backwards.

Pitfalls and Interview Angles

Pitfalls and Interview Angles

State leaking across tests. A session-scoped fixture that mutates shared state makes test order matter — the #1 cause of "passes alone, fails in suite." Keep shared fixtures read-mostly, or drop them to function scope.

Overrides. Redefining a fixture with the same name in a narrower conftest.py (or inside a test module) shadows the outer one — the built-in way to substitute a fake.

Visibility. pytest --setup-show prints the setup/teardown stack per test; pytest --fixtures lists what is available; -k plus --lf (last-failed) narrows a loop fast.

Interview angle: explain how pytest resolves a fixture — name lookup through conftest hierarchy, dependency graph construction, scope-ordered execution, teardown in reverse — and why autouse should stay rare: it hides setup cost in tests that never asked for it.

Quiz

1. What does yield inside a fixture provide?

Question 1 options

2. A session-scoped fixture needs a function-scoped one. What happens?

Question 2 options

3. How do you replace a fixture for one module only?

Question 3 options

Flashcards

Question

yield fixture

Answer

Provides the resource before yield; teardown code after yield always runs.

Question

Fixture scopes

Answer

function < class < module < package < session — wider scope reuses setup more.

Question

Scope dependency rule

Answer

A fixture may request only same-or-broader-scoped fixtures, never narrower.

Question

pytest --setup-show

Answer

Prints fixture setup/teardown ordering per test — first tool when state seems leaked.

Revision Notes

Key Takeaways

  • 1. Put reusable fixtures in conftest.py; use yield for guaranteed teardown
  • 2. Scope wider only for genuinely expensive, read-only setup to avoid order-dependent tests
  • 3. Parametrize combinatorics and override fixtures by redefining names in narrower scopes

Interview Tips

  • • Walk fixture resolution: conftest lookup → dependency graph → scope-ordered setup → reverse teardown
  • • Explain how you would debug a flaky suite: --setup-show, scope audit, isolate shared mutable state

Cheat Sheet

@pytest.fixture + yield = teardown; conftest.py shares; scopes function→session; same-or-broader requests only; @pytest.mark.parametrize; --setup-show.

Continue Learning

Before You Start

  • No prerequisites listed.

Next Topics