Updated Jun 30, 2026

Pytest, From Zero

You wrote some Python that works, and now you want a safety net so the next change doesn't quietly break it. You looked at the standard library's unittest, saw self.assertEqual and class boilerplate everywhere, and quietly closed the tab. Pytest is the tool most Python people actually reach for: you write assert x == y, run one command, and get a failure message that tells you exactly what went wrong. This guide takes you from zero to writing tests you'll keep.

How to read this

Read the phases in order the first time. Phase 1 builds the mental model: what pytest is, how it finds your tests with zero config, and why plain assert is the whole pitch. Phase 2 is the day-to-day: fixtures for setup and teardown, parametrize for running one test against many inputs, and marks for selecting what runs. Phase 3 is the harder edges: conftest.py, faking the outside world with monkeypatch, and the traps that waste an afternoon. If you already write pytest tests and want the gotchas, skim 1 and 2 and slow down on 3.

The phases

  1. The mental model: plain assert and zero-config discovery - what pytest is, how it finds tests, and why assert beats self.assertEqual.
  2. The everyday core: fixtures, parametrize, and marks - dependency-injected setup, table-driven tests, and selecting what runs.
  3. Production reality: conftest, monkeypatch, and the gotchas - sharing fixtures, faking the outside world, and the traps that bite.

Phase 1: The mental model: plain assert and zero-config discovery