Test Doubles

A track of P30 · Testing & Mocking.

Mocks and patching without the cargo cult: build a recording Mock and the patch swap-and-restore by hand, then double only the boundaries you don't own - network, time, payments - and run your own code for real.

Some collaborators cannot appear in a unit test. You will not charge a real card to check your checkout maths, call a live email server, or let the wall clock decide whether "expires tomorrow" is true. A test double stands in for them: a stunt actor that takes the dependency's place, plays the line you need, and - crucially - records how it was used so you can assert the interaction afterwards. unittest.mock gives you Mock for the stand-in and patch for the swap; this track builds tiny versions of both so neither is magic.

The mechanics are humbler than the reputation. A mock is an object that records every call and returns whatever you configured - you will write one whose .calls, .call_count and assert_called_with come from a plain list. patch is setattr(obj, name, double) with the original saved and restored on exit - which is exactly why the notorious rule holds: you patch a name where it is used, not where it is defined, because you are rebinding an attribute on the object that does the lookup. Build the swap-and-restore and that rule stops being a mantra and becomes obvious.

The hard part is not the tools but the restraint. Every mock removes real code from the test, so a suite that mocks everything is green and proves nothing - it asserts its own setup and shatters on the first refactor. The track closes on judgement: mock only the edges you do not own or cannot run - network, time, randomness, payments - and let the code you actually wrote run for real. A mock standing in for your own logic means you are testing the mock.

Mockrecord calls, return configured valuespatchswap where used, then restoreOnly at the boundaryrun your own code for real
Two small tools, one large piece of judgement - foundation upward.