pytest fixtures I keep copying between projects
Every project I touch ends up with the same four or five fixtures in conftest.py. Rather than copy them from the last repo again, here they are.
A workspace that cleans itself up
@pytest.fixture
def workspace(tmp_path, monkeypatch):
monkeypatch.chdir(tmp_path)
return tmp_path
Half of my tests write files. Changing into a temporary directory means a test can be sloppy about paths without leaving anything behind.
A clock I control
@pytest.fixture
def clock(monkeypatch):
now = [1_700_000_000.0]
def fake_time():
return now[0]
monkeypatch.setattr(time, "time", fake_time)
monkeypatch.setattr(time, "sleep", lambda s: now.__setitem__(0, now[0] + s))
return now
Retry loops and timeouts become instant and deterministic. Tests that used to take forty seconds now take milliseconds, and they no longer fail on a loaded CI runner.
Retrying a flaky call
def eventually(fn, timeout=10.0, interval=0.2):
deadline = time.time() + timeout
last = None
while time.time() < deadline:
try:
return fn()
except AssertionError as exc:
last = exc
time.sleep(interval)
raise last
Not a fixture, but it lives in the same file. When a test waits for a state change somewhere else, this replaces a hopeful sleep(5) with an explicit deadline and a real error message.
Capturing logs as structured records
caplog already does this, but I always want a small helper that returns just the messages at a given level, so assertions read as English rather than as tuple indexing.