Skip to content

unittest.mock.patch

unittest.mock.patch temporarily replaces an attribute, function, or object β€” for the duration of a test β€” with a Mock (or a value you specify), then automatically restores the original afterward. It’s how you test code that calls something you don’t want to actually run in a test: an API request, a database write, datetime.now(), os.remove.

Without patching, testing code that calls an external service means either actually calling it (slow, flaky, needs network/credentials) or manually saving and restoring the original function yourself:

import requests
def get_username(user_id):
response = requests.get(f"https://api.example.com/users/{user_id}")
return response.json()["name"]
# Testing this directly makes a real HTTP call every time you run the test
from unittest.mock import patch
def get_username(user_id):
response = requests.get(f"https://api.example.com/users/{user_id}")
return response.json()["name"]
@patch("requests.get")
def test_get_username(mock_get):
mock_get.return_value.json.return_value = {"name": "Alice"}
result = get_username(42)
assert result == "Alice"
mock_get.assert_called_once_with("https://api.example.com/users/42")
# after the test, requests.get is automatically restored to the real function
# As a context manager, for patching only part of a test function
def test_partial_patch():
with patch("requests.get") as mock_get:
mock_get.return_value.json.return_value = {"name": "Bob"}
assert get_username(1) == "Bob"
# requests.get is back to normal here, outside the `with` block
  • Isolates the unit under test: get_username’s logic is tested without a real network call β€” fast, deterministic, no external dependency needed to run the test suite.
  • Automatic cleanup: whether used as a decorator or context manager, the original is guaranteed restored even if the test raises an exception.
  • Built-in call assertions: mock_get.assert_called_once_with(...) verifies not just the return value, but that the mocked function was called correctly.
  • Patch where it’s looked up, not where it’s defined: @patch("requests.get") patches the name inside the requests module. If get_username did from requests import get instead, you’d need @patch("mymodule.get") β€” patching the name in the module that imported it, since that’s the reference actually being called.
  • The patched object is replaced with a MagicMock by default, which auto-creates attributes/methods on access β€” convenient, but it also means a typo like mock_get.return_vlaue silently creates a new mock attribute instead of raising an error.
  • patch.object(SomeClass, "method_name") patches a method on a specific class instead of a dotted string path β€” useful when the string-path form is awkward.
  • Multiple @patch decorators apply bottom-up, and their corresponding mock arguments are injected in the same bottom-up order β€” a common source of confusion when stacking several patches.
  1. What does unittest.mock.patch guarantee happens after the test, even if it fails?

    AnswerThe original object/function is automatically restored β€” patching is always undone, decorator or context-manager form.
  2. If mymodule.py does from requests import get and calls get(...), what do you patch β€” "requests.get" or "mymodule.get"?

    Answer`"mymodule.get"` β€” you patch the name where it's *looked up* (the importing module's namespace), not where it was originally defined.
  3. How do you assert that a mocked function was called with specific arguments?

    Answer`mock_obj.assert_called_once_with(expected_args)` (or `assert_called_with` if it may be called more than once).