Mock: patch(), spec/autospec & Testing Pitfalls
patch(): Temporary Substitution
# mymodule.py
import requests
def fetch_user(user_id):
response = requests.get(f"https://api.example.com/users/{user_id}")
return response.json()
# test_mymodule.py -- decorator form, scoped to the whole test function
from unittest.mock import patch
# CRITICAL: patch where the name is LOOKED UP (mymodule.requests.get),
# not where requests.get was originally defined. mymodule did
# `import requests` and calls requests.get -- that's the binding
# to patch. patching 'requests.get' directly would NOT affect
# mymodule's own reference to it.
@patch('mymodule.requests.get')
def test_fetch_user(mock_get):
mock_get.return_value.json.return_value = {"id": 1, "name": "Alice"}
result = fetch_user(1)
assert result == {"id": 1, "name": "Alice"}
mock_get.assert_called_once_with("https://api.example.com/users/1")
# Context manager form -- scoped to just the `with` block
def test_fetch_user_context():
with patch('mymodule.requests.get') as mock_get:
mock_get.return_value.json.return_value = {"id": 2}
assert fetch_user(2) == {"id": 2}
# original requests.get is restored here, automatically
# patch.object -- same effect, takes an object reference instead of a string path
with patch.object(SomeClass, 'method_name') as mock_method:
...
# Class-decorator form -- applies to EVERY test method in the class
@patch('mymodule.requests.get')
class TestUserFetching(unittest.TestCase):
def test_one(self, mock_get): ...
def test_two(self, mock_get): ...spec, autospec & PropertyMock
# Plain Mock accepts ANY attribute/call -- a typo silently "works"
plain = Mock()
plain.fethc_user() # typo, but no error -- just returns another Mock
# spec restricts the mock to the real class's actual attributes
from unittest.mock import create_autospec
specced = Mock(spec=RealApiClient)
specced.fethc_user() # AttributeError -- 'fethc_user' doesn't exist on RealApiClient
# create_autospec goes further: also validates call SIGNATURES,
# catching a wrong-argument-count call like the real callable would
auto = create_autospec(RealApiClient)
auto.fetch_user() # TypeError -- missing required argument
# PropertyMock -- needed to correctly mock a @property (a descriptor,
# not a regular callable attribute)
from unittest.mock import PropertyMock
with patch.object(type(obj), 'some_property', new_callable=PropertyMock) as mock_prop:
mock_prop.return_value = 'mocked value'
assert obj.some_property == 'mocked value'Why Mock External Dependencies
Real network/DB calls in unit tests are slow, flaky (network availability, external uptime), and sometimes costly (rate limits, paid API usage).
Mocking isolates the test to the code under test's own logic -- fast, deterministic, offline.
Risk of over-mocking: tests can keep passing against a stale mock configuration even after the real dependency's actual behavior changes -- complement with some integration/contract tests exercising real dependencies.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free