Learn pytest

Python's de facto test framework: plain asserts, fixtures and plugins

19 lessons · 3 hours · 4 levels · covers pytest 9.1

pytest is the most widely used testing framework for Python. It discovers tests automatically, turns plain assert statements into detailed failure reports, and manages setup through composable fixtures. A rich plugin ecosystem adds parallel runs, coverage, async support and framework integrations, which makes it the backbone of testing in most Python projects.

Before you start

pytest builds on these; the tree links to the exact lessons you need.

How deep do you want to go?

1. EssentialsRead and write simple code, do the everyday basics6 lessons · 54 min in total
2. PracticalUse it productively at work, with the usual idioms12 lessons · 2 hours in total
3. AdvancedThe less common features, performance and trade-offs16 lessons · 3 hours in total
4. ExpertInternals and the edge cases experts know19 lessons · 3 hours in total

The pytest tree

pytestWriting and running your first testsWriting and runningyour first testsAssertions and approxAssertions andapproxTesting exceptions with pytest.raisesTesting exceptionswith pytest.raisesRunning and selecting testsRunning andselecting testsFixtures: setup through argumentsFixtures: setupthrough argumentsParametrizing testsParametrizing testsFixture scope and yield teardownFixture scope andyield teardownBuilt-in fixtures: tmp_path, capsys, monkeypatchBuilt-in fixtures:tmp_path, capsys,…conftest.py and sharing fixturesconftest.py andsharing fixturesMarkers: skip, xfail and custom marksMarkers: skip, xfailand custom marksConfiguring pytest in pyproject.tomlConfiguring pytest inpyproject.tomlMocking with monkeypatch and unittest.mockMocking withmonkeypatch and u…Defining functionsDefining functionsModules and importsModules and importsExceptions in depthExceptions in depthContext managers and withContext managersand withpathlib for files and directoriespathlib for files anddirectoriesasync and await with asyncioasync and await withasyncioThe import systemThe import system
Essentials and Practical shown (12 of 19 lessons); the full list is below. Click a lesson to read it.

All 19 lessons, in order

Writing tests

  1. Writing and running your first tests · Essentials · 8 min

    Write test functions with plain assert in test_*.py files and run them with the pytest command.

  2. Assertions and approx · Essentials · 8 min

    Get detailed failure messages from plain asserts and compare floats safely with pytest.approx.

  3. Testing exceptions with pytest.raises · Essentials · 8 min

    Assert that code raises the right exception, check its message with match=, and inspect it via the ExceptionInfo.

  4. Parametrizing tests · Essentials · 10 min

    Run one test function over many inputs with @pytest.mark.parametrize, with readable ids for each case.

Running and selecting

  1. Running and selecting tests · Essentials · 8 min

    Run subsets of tests with node ids and -k, stop early with -x, rerun failures with --lf, and see output with -s.

  2. Markers: skip, xfail and custom marks · Practical · 10 min

    Skip tests conditionally, mark expected failures with xfail, and tag tests with custom markers you can select with -m.

Fixtures

  1. Fixtures: setup through arguments · Essentials · 12 min

    Define reusable test setup with @pytest.fixture and receive it by naming it as a test argument.

  2. Fixture scope and yield teardown · Practical · 12 min

    Clean up after tests with yield fixtures and share expensive resources across tests with scope='module' or 'session'.

  3. Built-in fixtures: tmp_path, capsys, monkeypatch · Practical · 12 min

    Use pytest's built-in fixtures for temporary files, captured output, environment changes and patching.

  4. Parametrized and factory fixtures · Advanced · 12 min

    Run every dependent test against several fixture variants with params=, use indirect parametrization, and build factory fixtures.

  5. autouse fixtures and fixture resolution · Advanced · 10 min

    Apply fixtures automatically with autouse, understand instantiation order, and override fixtures per module or with parametrize.

Organizing and extending the suite

  1. conftest.py and sharing fixtures · Practical · 10 min

    Share fixtures across files with conftest.py, understand its directory scoping, and lay out a test suite.

  2. Configuring pytest in pyproject.toml · Practical · 10 min

    Set testpaths, addopts, markers and strictness in pyproject.toml (or pytest.toml) so every run behaves the same.

  3. Plugins: xdist, coverage and asyncio · Advanced · 12 min

    Extend pytest with popular plugins: pytest-xdist for parallel runs, pytest-cov for coverage, pytest-asyncio for async tests.

Mocks, warnings and logs

  1. Mocking with monkeypatch and unittest.mock · Practical · 12 min

    Replace slow or external dependencies in tests with monkeypatch and Mock objects, and assert how they were called.

  2. Testing warnings and log output · Advanced · 10 min

    Assert on warnings with pytest.warns, on log records with caplog, and turn unexpected warnings into errors.

Internals and plugins

  1. Writing hooks and local plugins · Expert · 15 min

    Customize pytest itself with hook functions in conftest.py: add options, modify collected items and inspect test reports.

  2. How assertion rewriting works · Expert · 12 min

    How pytest rewrites assert statements at import time through an import hook, and when you must register helper modules.

  3. Collection, nodes and the runtest protocol · Expert · 14 min

    How pytest builds a tree of collector and item nodes, then runs each item through setup, call and teardown with fixture finalization.