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.

Arrangeset up inputsActcall it onceAssertcheck the result
Every test in this track - and every test in this repo - is these three beats.