Skip to main content
Back to Blog
Series Playlist

Python Test Systems

Eight pytest-centered guides for fixture design, parametrization, async isolation, property tests, parallel workers, and AI-assisted review.

Series Chapters (8)

Part 1 · Automation Tutorials

Design pytest Fixtures as Explicit Resource Contracts

A test that passes alone and errors in the full suite is almost never a flaky test — it is a fixture whose lifetime is wider than the state it holds, requested by nothing the test names. This guide works from what pytest actually reads when it orders fixtures, why one autouse fixture pulls its whole dependency graph into every test in scope, and why teardown after yield covers only the fixtures that already succeeded.

Sep 18, 202615 min read
Part 2 · Automation Tutorials

Use pytest Parametrization Without Hiding Test Intent

The generated ID is the only part of a parametrized case that reaches the report, the selection flag and the failure history — so an auto-generated one costs you both diagnosis and reproduction. This guide covers the exact rule pytest uses to build IDs, the default that silently renumbers collisions into positions, the effects that fire at collection time because a parameter table is just an expression in a decorator, and how to choose equivalence classes instead of Cartesian products.

Sep 19, 202612 min read
Part 3 · Automation Tutorials

Debug pytest-asyncio Event-Loop and Fixture Failures

pytest-asyncio gives one event loop per pytest collector, so every async resource is bound to the loop of whatever created it. That single fact explains attached to a different loop, Event loop is closed, ScopeMismatch on a fixture you never wrote, and the AttributeError on an async_generator that mentions no loop at all. This guide separates the five causes, gives a check that tells them apart, and starts with the two configuration defaults that do not match.

Sep 20, 202615 min read
Part 4 · Automation Tutorials

Run pytest in Parallel Without Shared-State Flakes

Adding workers does not create shared state — it reveals that the suite only ever worked because it ran one test at a time. This guide starts from the fact that every xdist worker collects independently and runs its own copy of each session-scoped fixture, then covers deriving a reclaimable namespace from worker_id, one PostgreSQL schema per worker, why collection order has to agree across workers, and why -s cannot work under xdist at all.

Sep 21, 202615 min read
Part 5 · Automation Tutorials

Property-Based Testing in Python: Start with Invariants

A property test asserting isinstance(encode(s), str) can run sixty thousand inputs and establish nothing, because no input in the domain could falsify it. This guide covers the three families of claim that can actually fail, why the default text alphabet is a decision rather than a default, constraining the domain in the strategy instead of with assume(), the correctness health check that catches function-scoped fixtures not resetting per input, and how to pin every shrunk counterexample so it never has to be rediscovered.

Sep 22, 202616 min read
Part 6 · Automation Tutorials

Build Deterministic Python API Test Data Factories

A duplicate-key violation blamed on parallelism, an assertion broken by a Faker patch bump, and a 41-line payload diff with two relevant fields all come from the same cause: generating data without deciding what is fixed, what varies, and what the test asserts. This guide covers the reseed-to-zero behaviour of the faker fixture, why generated values must never appear as expected outputs, deriving reproducible unique identity from the test node id with uuid5, and the jsonschema format checker that does nothing unless you switch it on.

Sep 23, 202613 min read
Part 7 · Automation Tutorials

Test Python Retry Logic Without Sleeping

In tenacity the sleeper is a constructor argument, so a retry test never needs to patch time.sleep or wait real seconds — pass a callable that records the delay and the list it collects is the backoff schedule. This guide covers asserting the schedule instead of the call count, bounding jittered waits using the documented formula rather than pinning the random source, enforcing a deadline against a clock the test owns, and why the exception your caller catches is not the one your code raised.

Sep 24, 202614 min read
Part 8 · AI in Testing

Review AI-Generated pytest Tests with Mutation Checks

A generated test file can execute every branch of a pricing rule and still pass when the threshold moves by one, because coverage records that a line ran and nothing records that an assertion depended on it. This guide covers scoping a mutmut run to a single function, telling a surviving mutant apart from a mutant that any calling test kills, the two review patterns — a mock placed one layer too low and an assertion that restates its own fixture — that make every mutant survive, and the pragmas and settings that quietly remove code from the run.

Sep 25, 202613 min read