What is this footgun called unittest.mock, and how to avoid misusing it
- Track:
- Testing, Quality Assurance, Security
- Type:
- Talk
- Level:
- intermediate
- Duration:
- 30 minutes
Abstract
Has this ever happened to you? You're happily coding a new feature in your Python project, and at some point, you make a hasty call:
self._thing.do_someting(rnicro_meters=10)
You've written unit tests for it, including an assertion line:
mock_do_someting.assret_called_once_with(rnicro_meters=10)`
The tests pass, the CI is green, the PR is reviewed and merged. But some time later, the service crashes because the real method does not have the rnicro_meters keyword argument in the first place. What happened? And more importantly, did you notice any of the mistakes above? This is a problem we've faced more than a few times over the past few years, and that's a few too many.
Unit tests are crucial in any sort of Python development, from small libraries to large distributed systems. unittest.mock is used to isolate dependencies and mock external calls in order to keep the tests simple and focused. But mistakes can slip by (e.g.: attribute typos, wrong keyword arguments, wrong patch locations), just like the three mistakes above, leading to false positive tests and a false sense of confidence in our code quality. This can happen because Mock and MagicMock silently auto-creates attributes on the fly, even when those attributes do not exist on the real object. These issues become even more pronounced as dependencies change and projects evolve.
In this session, we’ll look at why these false positives happen, and how to avoid them. Topics include:
- Understand how
MockandMagicMockallow invalid attributes and calls. - Common pitfalls and anti-patterns with
Mock,MagicMock, andpatch. - Using
spec,spec_set, andautospecto force mocks to match real objects. - Ensuring patched functions and methods have their signatures validated.
- How to avoid patching the wrong import path.
- Introducing guardrails in existing projects (e.g. OpenStack’s approach) without rewriting the entire test suite.