Advanced·15 min·engineering · testing · pytest · mock
pytest fixtures + mocking
Fixtures: dependency injection for tests
A fixture is a factory function pytest injects into any test that names it as an argument.
Why they matter
Without fixtures, every test starts with 5 lines of setup. With fixtures:
- Setup lives in one place.
- Each test gets a fresh instance (default scope=
"function"). - Fixtures can depend on other fixtures — composition for free.
Scopes
function(default) — new per test.class— shared across tests in one class.module— shared across a file.session— created once. Use for expensive stuff (real DB, browser).
Mocking with monkeypatch
The best mocking tool comes built into pytest:
def test_something(monkeypatch):
monkeypatch.setattr(mymodule, "send_email", fake_send)
# ... test uses fake_send until test ends, then auto-restored
Cleaner than unittest.mock.patch for most cases. Auto-undoes at test teardown.
unittest.mock when you need it
For call-tracking, MagicMock is unbeatable:
from unittest.mock import MagicMock
mock_client = MagicMock()
mock_client.fetch.return_value = {"ok": True}
service = MyService(mock_client)
service.do_thing()
mock_client.fetch.assert_called_once_with("some-arg")
Try it
- Add a
bobfixture that depends onrepo. - Write a test that monkeypatches
send_welcome_emailto raise, and assertssignupstill returns a valid uid (or handles the error — your choice, document it).