Python Pytest Cheat Sheet
Covers writing pytest test functions, fixtures with setup/teardown, parametrized tests, and the most useful command-line options.
Basic Test Functions
pytest discovers functions prefixed with test_.
# test_math.pydef add(a, b): return a + bdef test_add(): assert add(2, 3) == 5def test_add_raises(): import pytest with pytest.raises(TypeError): add("2", 3)# Run with: pytest# Run one file: pytest test_math.py# Run one test: pytest test_math.py::test_add# Verbose: pytest -v
Fixtures
Reusable setup/teardown for tests.
import pytest@pytest.fixturedef sample_data(): return {"id": 1, "name": "Alice"}def test_name(sample_data): assert sample_data["name"] == "Alice"@pytest.fixturedef db_connection(): conn = create_connection() yield conn # Provided to the test conn.close() # Teardown runs after the test@pytest.fixture(scope="session")def api_client(): return APIClient() # Created once per test session
Parametrized Tests
Run the same test body against many inputs.
import pytest@pytest.mark.parametrize("a,b,expected", [ (2, 3, 5), (0, 0, 0), (-1, 1, 0),])def test_add_parametrized(a, b, expected): assert add(a, b) == expected@pytest.mark.parametrize("value", [1, 2, 3])@pytest.mark.parametrize("multiplier", [10, 100])def test_stacked(value, multiplier): assert value * multiplier > 0 # Stacked marks -> 6 combinations
CLI Options & Markers
Common flags for running and filtering tests.
- pytest -k 'add'- Run only tests whose name matches a substring/expression
- pytest -m slow- Run only tests marked with @pytest.mark.slow
- pytest -x- Stop after the first failing test
- pytest --lf- Re-run only the tests that failed last time
- pytest -s- Show print() output (disable output capturing)
- pytest --cov=myapp- Report test coverage (requires the pytest-cov plugin)
- @pytest.mark.skip(reason=...)- Unconditionally skip a test
- @pytest.mark.xfail- Mark a test as expected to fail
Monkeypatching & Mocking
Replace attributes, env vars, and objects for the duration of a test.
def test_env_var(monkeypatch): monkeypatch.setenv("API_KEY", "test-key") monkeypatch.delenv("UNSET_ME", raising=False) assert os.environ["API_KEY"] == "test-key"def test_patch_function(monkeypatch): def fake_get(url): return {"status": 200} monkeypatch.setattr("requests.get", fake_get) assert fetch_status("http://x") == 200from unittest.mock import MagicMock, patchdef test_with_mock(): mock_client = MagicMock() mock_client.fetch.return_value = {"id": 1} assert mock_client.fetch()["id"] == 1 mock_client.fetch.assert_called_once()@patch("myapp.service.send_email")def test_notify(mock_send): notify_user("[email protected]") mock_send.assert_called_with("[email protected]")
tmp_path & File-Based Fixtures
Built-in fixtures for isolated filesystem testing.
def test_write_report(tmp_path): out = tmp_path / "report.txt" generate_report(out) assert out.read_text() == "OK\n"def test_multiple_files(tmp_path_factory): d = tmp_path_factory.mktemp("data") (d / "a.csv").write_text("1,2\n") assert (d / "a.csv").exists()def test_capture_output(capsys): print("hello") captured = capsys.readouterr() assert captured.out == "hello\n"def test_logging(caplog): import logging logging.getLogger("app").warning("disk low") assert "disk low" in caplog.text
Autouse Fixtures & Finalizers
Fixtures that run for every test automatically and register cleanup callbacks.
import pytest@pytest.fixture(autouse=True)def reset_singleton(): yield Cache.instance = None # Runs after every test in this scope, no opt-in needed@pytest.fixturedef temp_dir(request): path = make_dir() def cleanup(): remove_dir(path) request.addfinalizer(cleanup) # Alternative to yield-based teardown return path@pytest.fixturedef service(request): marker = request.node.get_closest_marker("slow") timeout = 30 if marker else 5 return Service(timeout=timeout) # Fixtures can inspect the requesting test's markers
Testing Async Code
pytest-asyncio adds support for coroutine test functions.
import pytest# pip install pytest-asyncio# pytest.ini: [pytest]\nasyncio_mode = auto@pytest.mark.asyncioasync def test_fetch(): result = await fetch_data("http://x") assert result["status"] == "ok"@pytest.fixtureasync def async_client(): client = await create_client() yield client await client.close()async def test_with_async_fixture(async_client): assert await async_client.ping()
Config & Built-in Fixtures
pytest.ini options and fixtures that ship with pytest itself.
- pytest.ini [pytest] markers=- Registers custom markers so `--strict-markers` doesn't flag typos
- addopts = -ra --strict-markers- Bakes default CLI flags into every pytest invocation
- request fixture- Gives a fixture access to the requesting test's node, params, and markers
- monkeypatch- Safely patches attrs/env/dict/sys.path, auto-reverted after the test
- capsys / capfd- Captures stdout/stderr at the Python or file-descriptor level
- caplog- Captures log records emitted via the logging module during a test
- pytest.approx(x)- Compares floats with tolerance instead of exact equality
- conftest.py- Auto-discovered, directory-scoped home for shared fixtures and hooks
Put shared fixtures in a conftest.py file — pytest auto-discovers it without an import, making its fixtures available to every test in that directory and its subdirectories.