Pytest Fixtures Tutorial: Scope, Teardown, and Parametrize

A practical pytest fixtures tutorial — fixture scopes, yield teardown, conftest.py, tmp_path, monkeypatch — plus parametrize with ids, stacking, and indirect fixtures.

This pytest fixtures tutorial is built on one mental model: fixtures set up the world your test needs (a database connection, a temp directory, a logged-in user), while parametrize runs the same test with different inputs (every edge case, one test function). Master both and your suite gets shorter, faster, and easier to read. Install pytest first ( pip install pytest ), then follow along — every test in this guide actually passes. What you'll learn What a fixture is and when to use one vs parametrize Fixture scopes: function, class, module, session Yield fixtures: teardown that always runs conftest.py : sharing fixtures across test files Built-in fixtures: tmp_path , monkeypatch , caplog @pytest.mark.parametrize : multiple args, readable ids, pytest.param marks Stacked parametrize (cartesian product) and indirect fixtures The mistakes that make fixture-heavy suites slow and flaky Step 1 — What a fixture is (and how it differs from parametrize) A fixture is a function that prepares something a test needs , declared with @pytest.fixture . Tests ask for it by naming it as a parameter — pytest injects it automatically: # test_cart.py import pytest def cart_total(items): return sum(item["price"] * item["qty"] for item in items) @pytest.fixture def cart(): """A fresh shopping cart for every test that asks for it.""" return [{"price": 10, "qty": 2}, {"price": 5, "qty": 3}] def test_cart_total(cart): assert cart_total(cart) == 35 def test_cart_has_two_lines(cart): assert len(cart) == 2 Run it with python -m pytest test_cart.py -v : both pass, and each got its own cart — the fixture ran twice. No setup methods, no classes: a fixture is just a function whose return value pytest injects into whoever asks for it. Compare with parametrize, which answers a different question —…

Explore