deep-mock

deep-mock is a Python mocking library that simplifies patching and handles the edge cases that the standard unittest.mock.patch cannot solve. With patch you have to target the exact location a name was imported into, and even then it misses anything computed at import time or stored away in a closure, cache, or singleton. deep-mock lets you patch a dependency once and have it apply everywhere.

What it does

Its MockSysModules context manager replaces a function or class in its source module, then propagates the mock to every module that imported it and reloads those modules so any module-level state is recomputed with the mocked value. On exit, everything is restored and reloaded back to the real values. For indirect dependencies (a module that imports from a module that imports the mocked name), import_and_reload_module forces a reload at the right point.

It also ships conveniences for testing: a fake_useless_decorator pass-through to neutralize decorators with side effects (auth, caching, tracing like @observe or @firestore.transactional), project-wide defaults via DeepMockConfig in conftest.py, and helpers like find_calls_in_mock_calls and print_all_mock_calls for inspecting call history.

How it's used

Install it with pip install deep-mock, then wrap the code under test in MockSysModules with a list of (module, attribute, mock) tuples:

from unittest.mock import Mock
from deep_mock import MockSysModules

mock_fetch = Mock(return_value={"id": "1", "name": "Test User"})

with MockSysModules([
    ("myapp.database", "fetch_user", mock_fetch),
]):
    from myapp.services import user_service
    assert user_service.get_user("1")["name"] == "Test User"

View it on GitHub