Python’s unittest.mock module provides mock objects and patching utilities for isolating units under test. from unittest.mock import Mock, MagicMock, patch, call, ANY, sentinel, create_autospec. Create: m = Mock() — records attribute access, calls, and keyword arguments automatically; m = MagicMock() — same but pre-wires __str__, __len__, __enter__/__exit__, etc. Set returns: m.method.return_value = 42; m.method.side_effect = ValueError("boom") — raise on call; m.method.side_effect = [1, 2, 3] — return successive values. Assert: m.method.assert_called_once_with(arg1, key=val); m.method.assert_called_with(...); assert m.method.call_count == 2. Patch: @patch("mymodule.requests.get") replaces during the test and restores after; with patch("os.path.exists", return_value=True):; @patch.object(MyClass, "method"). Spec: create_autospec(RealClass) — enforces the real class’s API. Async: AsyncMock (Python 3.8+) for coroutine mocks. Claude Code generates isolated unit tests, dependency injection helpers, protocol-safe mocks, and async mock patterns.
CLAUDE.md for unittest.mock
## unittest.mock Stack
- Stdlib: from unittest.mock import Mock, MagicMock, patch, call, ANY, AsyncMock
- Create: m = MagicMock()
- m.method.return_value = 42
- m.method.side_effect = [1, 2, StopIteration]
- Assert: m.method.assert_called_once_with("x", key="y")
- m.method.call_args_list == [call("a"), call("b")]
- Patch: @patch("mod.ClassName.method", return_value=99)
- with patch.object(obj, "attr", new_callable=MagicMock): ...
- Spec: m = create_autospec(MyClass, instance=True)
unittest.mock Mocking and Patching Pipeline
# app/mockutil.py — helpers, context mocks, call inspector, async, recorder
from __future__ import annotations
import functools
import sys
from contextlib import contextmanager
from typing import Any, Callable
from unittest.mock import (
ANY,
AsyncMock,
MagicMock,
Mock,
call,
create_autospec,
patch,
sentinel,
)
# ─────────────────────────────────────────────────────────────────────────────
# 1. Mock factories
# ─────────────────────────────────────────────────────────────────────────────
def make_mock(
return_value: Any = None,
side_effect: Any = None,
spec: "type | None" = None,
**attrs: Any,
) -> MagicMock:
"""
Create a configured MagicMock with common options in one call.
Example:
m = make_mock(return_value=42, spec=int)
m = make_mock(side_effect=ValueError("bad"))
m = make_mock(name="db.query", return_value=[{"id": 1}])
"""
kwargs: dict[str, Any] = {}
if side_effect is not None:
kwargs["side_effect"] = side_effect
elif return_value is not None:
kwargs["return_value"] = return_value
if spec is not None:
kwargs["spec"] = spec
m = MagicMock(**kwargs)
for k, v in attrs.items():
setattr(m, k, v)
return m
def make_autospec(obj: Any, instance: bool = False, **kwargs: Any) -> MagicMock:
"""
Create a spec-constrained mock using create_autospec.
instance=True produces a mock of an instance rather than the class.
Example:
from io import StringIO
buf_mock = make_autospec(StringIO, instance=True)
buf_mock.write("hello") # OK
buf_mock.nonexistent() # AttributeError — spec enforced
"""
return create_autospec(obj, instance=instance, **kwargs)
def make_context_manager_mock(
enter_value: Any = None,
exit_return: bool = False,
) -> MagicMock:
"""
Create a MagicMock suitable for use as a context manager.
Example:
conn_mock = make_context_manager_mock(enter_value=MagicMock())
with patch("mymodule.get_connection", return_value=conn_mock):
result = mymodule.run_query()
"""
m = MagicMock()
m.__enter__ = Mock(return_value=enter_value or m)
m.__exit__ = Mock(return_value=exit_return)
return m
def make_sequence_mock(values: list[Any]) -> MagicMock:
"""
Create a mock whose calls return successive values from a list.
After exhaustion the next call raises StopIteration.
Example:
clock = make_sequence_mock([1.0, 1.5, 2.0])
assert clock() == 1.0
assert clock() == 1.5
"""
m = MagicMock()
m.side_effect = iter(values)
return m
# ─────────────────────────────────────────────────────────────────────────────
# 2. Patch helpers
# ─────────────────────────────────────────────────────────────────────────────
@contextmanager
def patch_env(vars: dict[str, str]):
"""
Context manager that patches os.environ for the duration.
Example:
with patch_env({"API_KEY": "test-key", "DEBUG": "1"}):
result = mymodule.get_config()
"""
with patch.dict("os.environ", vars, clear=False):
yield
@contextmanager
def patch_time(fixed_time: float):
"""
Context manager that patches time.time and time.monotonic to return fixed_time.
Example:
with patch_time(1_700_000_000.0):
ts = mymodule.get_timestamp() # always returns 1700000000.0
"""
with patch("time.time", return_value=fixed_time), \
patch("time.monotonic", return_value=fixed_time):
yield
@contextmanager
def patch_open(content: "str | bytes" = "", mode_return: Any = None):
"""
Context manager that patches builtins.open with an in-memory buffer.
Example:
with patch_open("key=value\\nother=123"):
cfg = mymodule.load_config("/etc/myapp.conf")
"""
from io import BytesIO, StringIO
if isinstance(content, bytes):
buf = BytesIO(content)
mm = MagicMock()
mm.__enter__ = Mock(return_value=buf)
mm.__exit__ = Mock(return_value=False)
with patch("builtins.open", return_value=mm):
yield
else:
buf = StringIO(content)
mm = MagicMock()
mm.__enter__ = Mock(return_value=buf)
mm.__exit__ = Mock(return_value=False)
with patch("builtins.open", return_value=mm):
yield
# ─────────────────────────────────────────────────────────────────────────────
# 3. Call inspection helpers
# ─────────────────────────────────────────────────────────────────────────────
def call_args_list(m: Mock) -> list[tuple[tuple, dict]]:
"""
Return a plain list of (args, kwargs) tuples for every call on m.
Example:
m("a", 1)
m("b", key="v")
print(call_args_list(m)) # [('a',1), {}), (('b',), {'key':'v'})]
"""
return [(c.args, c.kwargs) for c in m.call_args_list]
def was_called_with_any(m: Mock, **kwargs: Any) -> bool:
"""
Return True if mock was ever called with matching keyword arguments.
Example:
m("x", timeout=30)
was_called_with_any(m, timeout=30) # True
"""
for c in m.call_args_list:
if all(c.kwargs.get(k) == v for k, v in kwargs.items()):
return True
return False
def nth_call_args(m: Mock, n: int = 0) -> tuple[tuple, dict]:
"""
Return (args, kwargs) for the n-th call (0-based).
Example:
m("first"); m("second", x=1)
print(nth_call_args(m, 1)) # (('second',), {'x': 1})
"""
c = m.call_args_list[n]
return c.args, c.kwargs
# ─────────────────────────────────────────────────────────────────────────────
# 4. Async mock helpers
# ─────────────────────────────────────────────────────────────────────────────
def make_async_mock(return_value: Any = None, side_effect: Any = None) -> AsyncMock:
"""
Create an AsyncMock for patching coroutine functions.
Example:
fetch = make_async_mock(return_value={"status": 200})
with patch("mymodule.fetch_data", fetch):
import asyncio
result = asyncio.run(mymodule.load())
"""
m = AsyncMock()
if side_effect is not None:
m.side_effect = side_effect
elif return_value is not None:
m.return_value = return_value
return m
# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
import asyncio
print("=== unittest.mock demo ===")
# ── make_mock basic usage ─────────────────────────────────────────────────
print("\n--- make_mock / call inspection ---")
db = make_mock()
db.query("SELECT 1")
db.query("SELECT 2", timeout=30)
print(f" call_count: {db.query.call_count}")
print(f" call_args_list: {call_args_list(db.query)}")
print(f" was_called_with timeout=30: {was_called_with_any(db.query, timeout=30)}")
print(f" 2nd call args: {nth_call_args(db.query, 1)}")
# ── side_effect sequence ──────────────────────────────────────────────────
print("\n--- make_sequence_mock ---")
ticker = make_sequence_mock([100.0, 101.5, 99.8])
for _ in range(3):
print(f" price: {ticker()}")
# ── context manager mock ──────────────────────────────────────────────────
print("\n--- make_context_manager_mock ---")
conn = make_context_manager_mock(enter_value=make_mock(return_value=[1, 2, 3]))
with conn as c:
result = c()
print(f" context result: {result}")
print(f" __enter__ called: {conn.__enter__.called}")
# ── patch.dict via patch_env ──────────────────────────────────────────────
print("\n--- patch_env ---")
import os
with patch_env({"MY_TEST_VAR": "hello_mock"}):
print(f" MY_TEST_VAR in env: {os.environ.get('MY_TEST_VAR')!r}")
print(f" after patch: {os.environ.get('MY_TEST_VAR')!r}")
# ── ANY matcher ───────────────────────────────────────────────────────────
print("\n--- ANY matcher ---")
logger = MagicMock()
logger.info("user %s logged in", "alice")
logger.info.assert_called_with("user %s logged in", ANY)
print(f" assert_called_with ANY: passed")
# ── create_autospec ───────────────────────────────────────────────────────
print("\n--- create_autospec ---")
class Calculator:
def add(self, a: int, b: int) -> int: ...
def divide(self, a: float, b: float) -> float: ...
calc = make_autospec(Calculator, instance=True)
calc.add.return_value = 5
result = calc.add(2, 3)
print(f" calc.add(2,3) = {result}")
try:
calc.nonexistent()
except AttributeError as e:
print(f" nonexistent() → AttributeError: {e}")
# ── async mock ────────────────────────────────────────────────────────────
print("\n--- make_async_mock ---")
async def run_async():
fetch = make_async_mock(return_value={"ok": True})
result = await fetch("https://api.example.com")
fetch.assert_awaited_once()
return result
result = asyncio.run(run_async())
print(f" async mock result: {result}")
# ── sentinel ──────────────────────────────────────────────────────────────
print("\n--- sentinel ---")
NOT_SET = sentinel.NOT_SET
def get_value(default=NOT_SET):
if default is NOT_SET:
return "computed"
return default
print(f" no default: {get_value()!r}")
print(f" explicit None: {get_value(None)!r}")
print(f" explicit default: {get_value('x')!r}")
print("\n=== done ===")
For the pytest-mock (PyPI) alternative — mocker.patch(...) and mocker.MagicMock() provide the same functionality as unittest.mock through a pytest fixture that automatically cleans up patches at test end without needing @patch decorators or with blocks — use pytest-mock in pytest-based projects for cleaner test code and automatic teardown; unittest.mock is always available with zero dependencies and works with both unittest.TestCase and pytest. For the responses / httpretty / respx (PyPI) alternatives — these libraries provide HTTP-level mocking that intercepts actual network requests; responses patches requests only, respx patches httpx, and httpretty patches at the socket level — use HTTP mocking libraries when testing code that talks to real HTTP endpoints; use unittest.mock.patch for unit-level dependency injection where you control the code boundary. The Claude Skills 360 bundle includes unittest.mock skill sets covering make_mock()/make_autospec()/make_context_manager_mock()/make_sequence_mock() factories, patch_env()/patch_time()/patch_open() context managers, call_args_list()/was_called_with_any()/nth_call_args() call inspectors, and make_async_mock() for coroutine patching. Start with the free tier to try mocking patterns and unittest.mock pipeline code generation.