Mocking & Patching Interview Questions & Answers
6 questions Updated 2026-06-18
Python interview questions on mocking and why it matters, Mock vs MagicMock, unittest.mock.patch and patching where it's used, return_value vs side_effect, call assertions, and autospec.
Mocking replaces a real dependency with a fake stand-in object that records how it was called and returns whatever you tell it to. You use it to isolate the code under test from slow, unreliable, or side-effecting collaborators — network calls, databases, the clock, third-party APIs.
from unittest.mock import Mock
service = Mock()
service.fetch.return_value = {"id": 1} # canned response
result = service.fetch("/users/1") # no real network call
result # {"id": 1}
service.fetch.assert_called_once() # verify it happened
Mocking makes tests fast, deterministic, and focused on your logic rather than the dependency's. Rule of thumb: mock at the boundaries of your system (I/O, external services), not your own pure functions.
Both auto-create attributes and methods on access. The difference: MagicMock
additionally supports magic (dunder) methods — __len__, __iter__,
__getitem__, __enter__/__exit__, etc. — so it can stand in for objects used
with len(), iteration, indexing, or with. A plain Mock raises on dunder
access.
from unittest.mock import Mock, MagicMock
m = Mock()
len(m) # TypeError — Mock has no __len__
mm = MagicMock()
mm.__len__.return_value = 3
len(mm) # 3 — magic methods supported
list(mm) # works — __iter__ is mocked too
patch() uses MagicMock by default, which is why patched objects "just work" in
most cases. Use MagicMock when the dependency relies on protocols/dunders; Mock
is fine for plain method calls.
patch temporarily replaces an object with a mock for the duration of a test,
as a decorator or a context manager, restoring the original afterward. The
critical rule is "patch where it's looked up, not where it's defined" — you patch
the name in the module that imports and uses it.
# app.py
from time import time
def stamp(): return time()
# test.py — patch the reference INSIDE app, not 'time.time'
from unittest.mock import patch
@patch("app.time") # where it's USED
def test_stamp(mock_time):
mock_time.return_value = 123
assert stamp() == 123
with patch("app.time") as mock_time: # context-manager form
mock_time.return_value = 123
Patching "time.time" here would fail, because app already bound its own time
name at import. Always target the importing module's namespace — this is the
single most common mocking mistake.
return_value sets a single fixed value the mock returns on every call.
side_effect is more powerful: assign a function (called with the same args),
an exception (which gets raised), or an iterable (returning a different value
per successive call).
from unittest.mock import Mock
m = Mock(return_value=42)
m(); m() # 42, 42 — always the same
m.side_effect = [1, 2, 3] # one per call
m(); m() # 1, then 2
m.side_effect = ValueError("boom")
m() # raises ValueError
m.side_effect = lambda x: x * 2
m(10) # 20 — computed from the arg
Use return_value for a constant stub, and side_effect to raise errors,
vary results across calls, or compute based on arguments. If both are set,
side_effect wins (unless it returns the sentinel DEFAULT).
Mocks record every call, so you verify interactions with the assert_called*
family. Check whether/how many times it was called and with what arguments,
and inspect history via call_args / call_args_list.
from unittest.mock import Mock, call
m = Mock()
m(1, 2)
m(3, key="v")
m.assert_called() # at least once
m.assert_called_once() # exactly once -> would FAIL here
m.assert_called_with(3, key="v") # the MOST RECENT call
m.assert_any_call(1, 2) # any call matched
m.assert_has_calls([call(1, 2), call(3, key="v")])
m.call_count # 2
Note assert_called_with checks only the last call — use assert_any_call or
assert_has_calls for earlier ones. Beware typos: a misspelled assertion (e.g.
assert_called_once_with -> assert_called_onced_with) silently passes, so spell
these carefully.
A normal mock accepts any attribute access or call signature, so it can hide bugs
— a test passes even if you call a method that doesn't exist or with wrong arguments.
Autospec (autospec=True, or create_autospec) builds the mock to match the
real object's API, so it rejects nonexistent attributes and mismatched signatures.
from unittest.mock import patch, create_autospec
class Api:
def fetch(self, url): ...
@patch("app.Api", autospec=True)
def test_it(MockApi):
api = MockApi()
api.fetch("/x") # OK — matches real signature
api.fetch() # TypeError — missing 'url'!
api.delete() # AttributeError — no such method
Autospec makes mocks stay in sync with the real interface, catching drift when the real API changes. The tradeoff is a small overhead, but it's strongly recommended for non-trivial dependencies.
Practice tests are coming soon
Get notified when interactive mock interviews and quizzes launch.