How to Mock a Function Call in Python with unittest.mock
Use unittest.mock.Mock to wrap a function and spy on its call count and arguments in Python.
Python code
28 linesimport random
from unittest.mock import Mock, patch
def select_n_plus_one(numbers: list[int]) -> int:
"""Return the first number that appears more than once, if any."""
seen = set()
for num in numbers:
if num in seen:
return num
seen.add(num)
return -1
def detect_mock(select_func, numbers: list[int]) -> int:
"""Wrap a selector function with a mock to spy on calls."""
mocked = Mock(wraps=select_func)
result = mocked(numbers)
print(f"Called {mocked.call_count} time(s)")
print(f"Args: {mocked.call_args}")
return result
if __name__ == "__main__":
sample = [3, 1, 4, 1, 5, 9]
selector = select_n_plus_one
dup = detect_mock(selector, sample)
print(f"Duplicate: {dup}")
Output
Called 1 time(s)
Args: call([3, 1, 4, 1, 5, 9])
Duplicate: 1
How it works
Mock(wraps=select_func) creates a mock that forwards calls to the original function while recording call metadata. The call_count attribute increments with each call, and call_args stores the arguments as a call object. Calling the mock executes the wrapped function and returns its result, so the actual logic still runs. This pattern is useful for testing without altering behavior, and the mock can also track multiple calls with call_args_list.
Common mistakes
- Forgetting `wraps=` — without it, the mock returns a new Mock instead of the real function's result.
- Using `assert_called_once()` on a mock that is called more than once, causing test failures.
- Assuming `call_args` is a plain tuple — it's a `call` object that behaves like a tuple.
- Not restoring the original function in tests if using `patch` instead of `wraps`.
Variations
- Use `patch('module.function')` to replace a function globally during a test.
- Use a custom spy class that records calls and still executes the original logic.
Real-world use cases
- Verifying that a query function is called exactly once in a performance-critical database access path.
- Recording arguments passed to an external API client while still making the actual network call in integration tests.
- Instrumenting a production code path to measure call frequency without changing the function's behavior.
Sponsored
More from Database scaling & optimization
- Approximate Count with HyperLogLog in Python medium
- B-Tree Insert and In-Order Traversal in Python hard
- Broadcast a Small Reference Table in Python easy
- Build a Full Text Search Index in Python medium
- Build a Partial Index Mock in Python for Database Filtering easy
- Composite index leftmost prefix in Python medium
Keep learning
Related tutorials and quizzes for this topic.