Talk

Hot-swapping Symbols During Tests: Demystifying unittest.mock[.patch]

LanguageEnglish
Audience levelIntermediate
Elevator pitch

If it looks like a duck and quacks like a duck, it must be a duck. The unittest.mock stdlib provides a powerful mocking framework for unit tests with dynamic, ephemeral patching—but how does it work behind the scenes?

Abstract

When a Python object has the same attributes and methods as another object, it can be implicitly used interchangeably with that object at runtime.

The flexibility this “duck typing” provides can sometimes prove helpful in normal business logic, but is exceptionally advantageous when writing deterministic and isolated unit tests (which should be as self-contained and hermetic as possible). Eliminating external sources of failure limits flakiness and unwanted variance‒-no flaky network connections, no filesystems having permission issues, and definitely no time.sleeps slowing things down.

This is where “mocks” come in. By using a fake object that /looks/ like the real one but actually does /nothing/, we can ~trick the real code to run the logic we want to test, but avoid the side-effects that it usually comes with. The unittest.mock stdlib provides resources for creating mock objects as well as the ability to dynamically patch/unpatch these mocks over real code temporarily. While other languages rely on interfaces and code-gen for creating mocks, unittest.mock provides “Magic Mocks” with autospec-ing to dynamically copy and enforce the attributes at runtime.

Creating these mocks and injecting them (also known as patching) for the scope of a single unit test scope, while ensuring they are reset afterwards, is more complicated than may meet the eye. The unittest.mock library has a lot of behind-the-scenes machinery (and just as many associated gotchas) to facilitate this ephemeral hot-swapping of mocks into live code.

After this talk, listeners should come away with a deep understanding of how unittest.mock and unittest.mock.patch are implemented internally, allowing them to write better unit tests, and avoid running into confounding barriers of confusion to why their mock patching is mysteriously not working as-expected.

This talk is targeted towards intermediate programmers. A basic understanding of Python objects and the import system is preferred, but not strictly necessary. It will also help to have some prior knowledge of writing unit tests.

TagsAPIs, Testing, Language and features
Participant

Bryce Beagle

Software Engineer in California working on backend infrastructure and developer tooling.

Passionate about Python, Rust, urbanism, and transit