Claude Code for unittest.mock: Python Mocking and Patching — Claude Skills 360 Blog
Blog / AI / Claude Code for unittest.mock: Python Mocking and Patching
AI

Claude Code for unittest.mock: Python Mocking and Patching

Published: December 30, 2028
Read time: 5 min read
By: Claude Skills 360

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.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free