pytest Foundations
A track of P30 · Testing & Mocking.
Rebuild pytest's core by hand - the raises context manager, yield fixtures and a parametrize decorator - then read coverage as a signal, not a goal, with this repo's own make quality gate as the worked example.
A test is a small, selfish thing: it arranges an input, calls your code once,
and asserts what should be true. pytest barely adds to that - it finds every
test_* function for you, gives assert readable failure output, and hands you
one context manager, pytest.raises, for the case where the code is supposed
to blow up. That is nearly the whole tool. The practice panel grading you on
this very page is itself a from-scratch test_* runner, which is why this track
teaches pytest by having you rebuild its pieces rather than memorise its API.
The through-line is that none of it is magic. pytest.raises is an ordinary
context manager - the __enter__/__exit__ pair from P29 - so you write it.
A fixture is a generator with a yield splitting setup from teardown, driven in
a try/finally so cleanup runs even when a test fails - P29's yield-doorway,
pointed at testing. @parametrize is the three-layer decorator factory from
P29's @retry(times), expanding one test over a table of cases. Build each and
the framework stops being incantation and becomes code you could have written.
The track closes on judgement, not machinery: coverage. It is a powerful signal
and a treacherous target - it measures which lines ran, never whether you
checked what they did, so a suite that asserts nothing can still read 100%.
The last module makes coverage honest: a lower bound that finds untested code,
while the goal stays coverage of behaviour. This is the worked example the whole
Advanced Python discipline points back to - the make quality pytest gate you
are standing inside.