Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python unittest.mock: patch the name the caller actually resolves

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A patch replaces a selected name for the duration of a test; the caller must resolve that exact name for the patch to affect it.

Download Python source kit

Operation contract

The owned temporary module imports a clock function into its namespace. Patching the original source module after that import leaves the captured reference untouched. Patching the consumer module name changes the value read by the function. The test uses a small owned module and restores the patched name when the context exits. It prints stable numeric values rather than mocking a third-party service.

Failure and ownership boundary

Patching sys.modules and sys.path in a real test suite needs isolation; this fixture cleans up only its owned name. Broad mocks can hide changes in call signatures. A fake clock passed as an argument is simpler when code permits it; patching is useful for legacy lookup sites. Python testing: inject a clock to test expiry at the exact boundary and Python unittest.mock: inject a collaborator failure before publication cover the two approaches.

Working program

python
import importlib
import sys
import tempfile
from pathlib import Path
from unittest.mock import patch

with tempfile.TemporaryDirectory() as directory:
    Path(directory, "aitrove_clock_source.py").write_text("def time_value():\n    return 10\n", encoding="utf-8")
    Path(directory, "aitrove_clock_consumer.py").write_text("from aitrove_clock_source import time_value\ndef read():\n    return time_value()\n", encoding="utf-8")
    sys.path.insert(0, directory)
    importlib.invalidate_caches()
    try:
        source = importlib.import_module("aitrove_clock_source")
        consumer = importlib.import_module("aitrove_clock_consumer")
        with patch.object(source, "time_value", return_value=20):
            print("source patch:", consumer.read())
        with patch.object(consumer, "time_value", return_value=30):
            print("consumer patch:", consumer.read())
    finally:
        for name in ("aitrove_clock_consumer", "aitrove_clock_source"):
            sys.modules.pop(name, None)
        sys.path.remove(directory)

Output

Output
source patch: 10
consumer patch: 30

Costs and limits

Each patch changes one module attribute temporarily. The filesystem and module imports dominate this tiny test’s cost. It does not measure production lookup overhead or prove other consumers use the same name.

Common Mistakes

  • Patch the consumer lookup site, not only the function’s defining module.
  • Use owned module names and restore test changes to process-wide import state.

Connected lessons

Python unittest.mock: inject a collaborator failure before publication, Python testing: inject a clock to test expiry at the exact boundary, Python module cache: repeated imports reuse an owned module object.

python
patch-lookup-tests
Storage details