Unit tests are only valuable when they test one thing in isolation. The moment your function reaches out to a database, a live API, the file system, or the system clock, your test is no longer testing your code alone — it is testing every dependency your code touches. @unittest.mock.patch solves this by temporarily swapping any real object in your code's namespace for a controlled substitute, called a mock, for the exact duration of a single test.
The term mock is often used loosely to mean any substitute object in a test. In practice there is a more precise vocabulary, originating in Gerard Meszaros's work on xUnit test patterns. Understanding where patch fits in this vocabulary clarifies what you should reach for and when.
wraps= in patch creates a spy.patch().patch; written by hand.None or any sentinel value.Knowing this taxonomy prevents overuse of patch. If you only need a fixed return value and will never assert on the call, a stub is sufficient — a plain MagicMock(return_value=x) without any assert_called usage. If you need the real function to run but want to observe it, that is the wraps= spy pattern. Reserve full mocking — and therefore full patch() — for cases where you need both: controlled behavior and call verification.
unittest.mock has been part of Python's standard library since Python 3.3. The module provides the Mock class, the MagicMock class, and several patching helpers. patch is the most widely used of those helpers. It is a decorator, a context manager, and a callable that returns a patcher object — all three interfaces share the same underlying mechanism. This article walks through each pattern with full, runnable code examples and explains every parameter worth knowing.
What patch Is and How It Works
At the lowest level, patch is a function that performs two operations on a target attribute: it saves the original value, replaces it with a mock, and registers a cleanup function that restores the original when the test scope ends. Python's module system makes this possible because every name a module has imported lives as an attribute on that module object. patch uses getattr to retrieve the original and setattr to install the replacement. When the scope ends, it calls setattr again with the saved original.
The target you provide to patch is a dotted string in the format 'package.module.attribute'. The string must be importable from the environment where the test runs.
The target is imported when the decorated test function is called, not when the decorator is applied at class definition time. This distinction matters when the module containing the target is imported lazily.
The lookup rule: patch where the name is used, not where it is defined
This is the rule that causes the most confusion. Suppose you have a module called reports.py that imports datetime to stamp the current date onto a generated report:
# reports.py
import datetime
def generate_report(title: str) -> str:
today = datetime.date.today()
return f"{title} — generated on {today}"
When generate_report calls datetime.date.today(), Python looks up the name datetime in reports's namespace, then calls .date.today() on whatever object it finds there. The correct target string is therefore 'reports.datetime', because that is the name inside the module where the lookup actually happens at runtime.
If instead you had written from datetime import date inside reports.py, the local name in reports's namespace would be date, not datetime. In that case the correct target would be 'reports.date'. Patching 'datetime.date' directly would replace the object in the datetime module's namespace, but reports.py already holds its own binding to the original, so your patch would have no effect on it.
# reports.py — version 2: uses a direct import
from datetime import date
def generate_report(title: str) -> str:
today = date.today()
return f"{title} — generated on {today}"
# test_reports.py
import unittest
from unittest.mock import patch, MagicMock
import datetime
import reports
class TestGenerateReport(unittest.TestCase):
# WRONG: patches datetime.date in the datetime module itself,
# but reports.py already has its own 'date' binding — no effect.
@patch('datetime.date')
def test_wrong_target(self, mock_date: MagicMock) -> None:
mock_date.today.return_value = datetime.date(2026, 1, 1)
result = reports.generate_report("Q1 Summary")
# The real today() is still called; this test does not control the date.
# CORRECT: patches the 'date' name inside reports's own namespace.
@patch('reports.date')
def test_correct_target(self, mock_date: MagicMock) -> None:
mock_date.today.return_value = datetime.date(2026, 1, 1)
result = reports.generate_report("Q1 Summary")
self.assertEqual(result, "Q1 Summary — generated on 2026-01-01")
if __name__ == '__main__':
unittest.main()
patch() uses setattr on the module namespace where the name is looked up at runtime — not where the object was originally defined. Press Esc or click outside to close.
Enter your module name, what you want to patch, and how it was imported. The resolver outputs the correct patch target string.
Mock vs MagicMock
When patch replaces your target object, it installs a MagicMock by default. MagicMock is a subclass of Mock with all common dunder methods pre-configured, which means it can be used wherever Python expects magic method support — for example, as a context manager, as an iterable, or in a with statement. A plain Mock does not have these pre-built, so you would need to configure them yourself. For the overwhelming majority of patching scenarios, the default MagicMock is the right choice. Use plain Mock when you specifically want to verify that a mock is not a callable context manager or iterable, which protects against accidentally passing your mock in places that would silently consume those magic methods.
| Class | Dunder methods pre-built | Default in patch() | Typical use |
|---|---|---|---|
Mock |
None — must configure manually | No | Simple callable stubs with no magic method needs |
MagicMock |
Yes — __str__, __len__, __enter__, __exit__, and more | Yes | Context managers, iterables, and general-purpose patching |
AsyncMock |
Yes — async variants of call and context manager protocol | Yes, for async callables | Coroutines and async context managers |
NonCallableMock |
None | No | Patching non-callable attributes like constants or properties |
async def coroutine function?app/mailer.py contains from smtplib import SMTP. Which patch target is correct?Three Ways to Call patch
1. As a decorator on a test method
This is the most common form. The decorator wraps the test function, starts the patcher before the function body runs, and stops it afterward. Each @patch decorator adds one positional argument to the test method. The argument receives the mock object that was installed in place of the target:
# mailer.py
import smtplib
def send_welcome_email(address: str) -> bool:
with smtplib.SMTP('smtp.example.com', 587) as server:
server.sendmail('[email protected]', address, 'Welcome!')
return True
# test_mailer.py
import unittest
from unittest.mock import patch, MagicMock
import mailer
class TestSendWelcomeEmail(unittest.TestCase):
@patch('mailer.smtplib.SMTP')
def test_sends_to_correct_address(self, mock_smtp_class: MagicMock) -> None:
# SMTP() is now mock_smtp_class.
# Calling smtplib.SMTP(...) returns mock_smtp_class.return_value,
# which is itself a MagicMock that supports the context manager protocol.
mock_server = mock_smtp_class.return_value.__enter__.return_value
result = mailer.send_welcome_email('[email protected]')
self.assertTrue(result)
mock_smtp_class.assert_called_once_with('smtp.example.com', 587)
mock_server.sendmail.assert_called_once_with(
'[email protected]', '[email protected]', 'Welcome!'
)
if __name__ == '__main__':
unittest.main()
Stacking multiple decorators
When you need to patch more than one object in the same test, stack @patch decorators. Decorators are applied bottom-up — the decorator closest to the def line is applied first, which means it corresponds to the first extra argument in the method signature. The topmost decorator corresponds to the last argument.
# uploader.py
import os
import requests
def upload_file(path: str) -> int:
if not os.path.exists(path):
raise FileNotFoundError(path)
with open(path, 'rb') as f:
response = requests.post('https://api.example.com/upload', data=f)
return response.status_code
# test_uploader.py
import unittest
from unittest.mock import patch, MagicMock, mock_open
import uploader
class TestUploadFile(unittest.TestCase):
# Bottom decorator → first mock argument (mock_exists)
# Top decorator → last mock argument (mock_post)
@patch('uploader.requests.post') # applied second → mock_post
@patch('uploader.os.path.exists') # applied first → mock_exists
def test_successful_upload(self, mock_exists: MagicMock, mock_post: MagicMock) -> None:
mock_exists.return_value = True
mock_response = MagicMock()
mock_response.status_code = 200
mock_post.return_value = mock_response
with patch('builtins.open', mock_open(read_data=b'file content')):
status = uploader.upload_file('/tmp/report.pdf')
self.assertEqual(status, 200)
mock_exists.assert_called_once_with('/tmp/report.pdf')
mock_post.assert_called_once()
@patch('uploader.requests.post')
@patch('uploader.os.path.exists')
def test_raises_when_file_missing(self, mock_exists: MagicMock, mock_post: MagicMock) -> None:
mock_exists.return_value = False
with self.assertRaises(FileNotFoundError):
uploader.upload_file('/tmp/missing.pdf')
# requests.post should never have been called
mock_post.assert_not_called()
if __name__ == '__main__':
unittest.main()
2. As a context manager
Using patch as a context manager with the with statement gives you fine-grained control over exactly which lines of code run with the mock installed. The mock is only active for the duration of the with block:
# test_reports_context.py
import unittest
from unittest.mock import patch, MagicMock
import datetime
import reports
class TestGenerateReportContextManager(unittest.TestCase):
def test_report_date_is_controlled(self) -> None:
fixed_date = datetime.date(2026, 6, 15)
with patch('reports.date') as mock_date:
mock_date.today.return_value = fixed_date
result = reports.generate_report("Mid-Year Review")
# Outside the with block, reports.date is the real datetime.date again.
self.assertIn("2026-06-15", result)
self.assertIn("Mid-Year Review", result)
if __name__ == '__main__':
unittest.main()
The context manager form is particularly readable when you have complex setup logic that should only partially run under a mock, or when you want to mix real and mocked calls within the same test method.
3. As a patcher started and stopped manually
For situations where you need a mock to stay active across multiple test methods — such as in setUp and tearDown — you can call patch directly to get a patcher object, start it explicitly, and stop it in cleanup:
# test_service_setup.py
import unittest
from unittest.mock import patch
import mailer
class TestMailerWithSetup(unittest.TestCase):
def setUp(self) -> None:
# Start the patcher and register cleanup so tearDown is never forgotten.
patcher = patch('mailer.smtplib.SMTP')
self.mock_smtp_class = patcher.start()
self.addCleanup(patcher.stop) # addCleanup is safer than tearDown
# Configure a shared mock server instance for all test methods.
self.mock_server = self.mock_smtp_class.return_value.__enter__.return_value
def test_sends_correct_subject(self) -> None:
mailer.send_welcome_email('[email protected]')
self.mock_server.sendmail.assert_called_once()
def test_smtp_connects_to_correct_host(self) -> None:
mailer.send_welcome_email('[email protected]')
self.mock_smtp_class.assert_called_with('smtp.example.com', 587)
if __name__ == '__main__':
unittest.main()
Always prefer self.addCleanup(patcher.stop) over tearDown when manually starting patchers. addCleanup runs even if setUp raises an exception partway through, so it is impossible to forget a stop call and leak a patched object into subsequent tests.
patch.object — patching by object reference
patch.object takes a live Python object and a string attribute name instead of a dotted path string. This is useful when you already have a reference to the class or module you want to patch, and you want your test to fail at load time if the attribute does not exist rather than at runtime:
# payment.py
import stripe
class PaymentProcessor:
def charge(self, amount_cents: int, token: str) -> str:
charge = stripe.Charge.create(
amount=amount_cents,
currency="usd",
source=token,
)
return charge.id
# test_payment.py
import unittest
from unittest.mock import patch, MagicMock
import stripe
from payment import PaymentProcessor
class TestPaymentProcessor(unittest.TestCase):
@patch.object(stripe.Charge, 'create')
def test_charge_returns_charge_id(self, mock_create: MagicMock) -> None:
mock_charge = MagicMock()
mock_charge.id = 'ch_test_abc123'
mock_create.return_value = mock_charge
processor = PaymentProcessor()
charge_id = processor.charge(5000, 'tok_visa')
self.assertEqual(charge_id, 'ch_test_abc123')
mock_create.assert_called_once_with(
amount=5000,
currency="usd",
source='tok_visa',
)
if __name__ == '__main__':
unittest.main()
patch.dict — patching dictionaries and os.environ
patch.dict patches a dictionary for the duration of the test. Entries you provide are merged in; entries absent from your patch remain unchanged. When the test ends, the dictionary is restored to its original state. This is the standard way to control environment variables in tests without touching os.environ directly:
# config.py
import os
def get_database_url() -> str:
url = os.environ.get('DATABASE_URL')
if not url:
raise OSError("DATABASE_URL is not set")
return url
# test_config.py
import unittest
import os
from unittest.mock import patch
from config import get_database_url
class TestGetDatabaseUrl(unittest.TestCase):
@patch.dict(os.environ, {'DATABASE_URL': 'postgresql://localhost/testdb'})
def test_returns_database_url(self) -> None:
url = get_database_url()
self.assertEqual(url, 'postgresql://localhost/testdb')
@patch.dict(os.environ, {}, clear=True) # clear=True removes ALL env vars
def test_raises_when_var_missing(self) -> None:
with self.assertRaises(OSError):
get_database_url()
if __name__ == '__main__':
unittest.main()
Configuring Mocks: return_value, side_effect, and Assertions
Installing a mock is only half the work. The other half is configuring what the mock does when called, and then asserting that your code interacted with it in the expected way.
return_value
return_value is the value a mock returns every time it is called as a function. You can set it at construction time or afterward. When you patch a class, return_value represents what the class constructor returns — that is, the instance:
# inventory.py
from __future__ import annotations
import boto3
def list_s3_objects(bucket: str) -> list[str]:
s3 = boto3.client('s3')
response = s3.list_objects_v2(Bucket=bucket)
return [obj['Key'] for obj in response.get('Contents', [])]
# test_inventory.py
import unittest
from unittest.mock import patch, MagicMock
import inventory
class TestListS3Objects(unittest.TestCase):
@patch('inventory.boto3.client')
def test_returns_object_keys(self, mock_client_constructor: MagicMock) -> None:
# mock_client_constructor() is what boto3.client('s3') returns.
mock_s3 = mock_client_constructor.return_value
mock_s3.list_objects_v2.return_value = {
'Contents': [
{'Key': 'reports/q1.pdf'},
{'Key': 'reports/q2.pdf'},
]
}
keys = inventory.list_s3_objects('my-data-bucket')
self.assertEqual(keys, ['reports/q1.pdf', 'reports/q2.pdf'])
mock_client_constructor.assert_called_once_with('s3')
mock_s3.list_objects_v2.assert_called_once_with(Bucket='my-data-bucket')
@patch('inventory.boto3.client')
def test_returns_empty_list_when_bucket_empty(self, mock_client_constructor: MagicMock) -> None:
mock_s3 = mock_client_constructor.return_value
mock_s3.list_objects_v2.return_value = {} # no 'Contents' key
keys = inventory.list_s3_objects('empty-bucket')
self.assertEqual(keys, [])
if __name__ == '__main__':
unittest.main()
side_effect
side_effect gives you finer control than return_value. It takes priority over return_value when both are set. There are three forms:
- An exception class or instance: the mock raises it every time it is called.
- A callable: the mock calls it with the same arguments it received and returns the result. This lets you write a real function that inspects the arguments and returns different values.
- An iterable: each successive call to the mock pops the next value from the iterable. If the value is an exception, it is raised rather than returned.
# fetcher.py
from __future__ import annotations
import requests
def fetch_with_retry(url: str, attempts: int = 3) -> dict | None:
for i in range(attempts):
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
return response.json()
except requests.RequestException:
if i == attempts - 1:
raise
return None
# test_fetcher.py
import unittest
from unittest.mock import patch, MagicMock
import requests
import fetcher
class TestFetchWithRetry(unittest.TestCase):
@patch('fetcher.requests.get')
def test_raises_on_connection_error(self, mock_get: MagicMock) -> None:
# side_effect as an exception: every call raises ConnectionError
mock_get.side_effect = requests.ConnectionError("refused")
with self.assertRaises(requests.ConnectionError):
fetcher.fetch_with_retry('https://api.example.com/data')
# Three attempts were made before giving up
self.assertEqual(mock_get.call_count, 3)
@patch('fetcher.requests.get')
def test_succeeds_after_two_failures(self, mock_get: MagicMock) -> None:
# side_effect as an iterable: fail twice, succeed on the third call
ok_response = MagicMock()
ok_response.json.return_value = {'status': 'ok'}
ok_response.raise_for_status.return_value = None
mock_get.side_effect = [
requests.ConnectionError("attempt 1"),
requests.ConnectionError("attempt 2"),
ok_response,
]
result = fetcher.fetch_with_retry('https://api.example.com/data')
self.assertEqual(result, {'status': 'ok'})
self.assertEqual(mock_get.call_count, 3)
@patch('fetcher.requests.get')
def test_side_effect_as_callable(self, mock_get: MagicMock) -> None:
# side_effect as a callable: inspect arguments and return accordingly
def dynamic_response(url: str, **kwargs: object) -> MagicMock:
if 'timeout' not in kwargs:
raise ValueError("timeout required")
response = MagicMock()
response.json.return_value = {'url': url}
response.raise_for_status.return_value = None
return response
mock_get.side_effect = dynamic_response
result = fetcher.fetch_with_retry('https://api.example.com/items')
self.assertEqual(result['url'], 'https://api.example.com/items')
if __name__ == '__main__':
unittest.main()
Use when
You need the mock to return the same value every time it is called, regardless of arguments. The simplest and most common case.
Syntax
mock.return_value = {'status': 'ok'}
Or at creation: MagicMock(return_value=True)
Precedence
Used by default. If side_effect is also set, side_effect wins and return_value is ignored unless the side_effect callable returns DEFAULT.
Classic mistake
Forgetting that patching a class means mock.return_value is the instance — so configure methods on mock.return_value.method, not on mock.method.
Use when
You need the mock to raise an exception every time it is called — simulating a network timeout, permission error, or any failure path.
Syntax
mock.side_effect = requests.ConnectionError("refused")
Pass an exception instance or class — both work.
Why not just raise in the body?
You cannot raise inside a decorator argument. side_effect is how you declaratively wire up exception raising to a specific mock call, without touching test body flow.
Deeper use
Mix with the iterable form: put exceptions and normal return values in the same list to simulate flaky APIs — first call fails, second succeeds, third fails again.
Use when
The mock is called multiple times in sequence and each call should return (or raise) something different — retry logic, pagination, or multi-step protocols.
Syntax
mock.side_effect = [err1, err2, good_response]
Exception instances in the list are raised; all other values are returned.
When the list is exhausted
If the mock is called more times than there are entries in the list, StopIteration is raised. Always ensure your list is at least as long as the expected call count.
Deeper use
Use itertools.chain or a generator to produce an infinite or conditionally-terminated sequence — useful for long-running loop tests that pull from a queue.
Use when
The return value must depend on the arguments the mock receives at call time — dynamic routing, argument-dependent error injection, or delegating to a simplified real implementation.
Syntax
def my_side_effect(url, **kw):
return {'url': url}
mock.side_effect = my_side_effect
Return DEFAULT to fall through
If your callable returns unittest.mock.DEFAULT, the mock falls back to using return_value. This lets you conditionally intercept only some calls.
Deeper use
Assign a callable that checks a shared state dictionary — mock responses that evolve as the test progresses, simulating a stateful API where each call changes server-side data.
Assertion methods on mocks
Every mock object tracks every call made to it. The following assertion methods are available on any Mock or MagicMock instance, and they raise AssertionError on failure:
| Method | What it asserts |
|---|---|
assert_called() |
The mock was called at least once |
assert_not_called() |
The mock was never called |
assert_called_once() |
The mock was called exactly once |
assert_called_with(*args, **kwargs) |
The most recent call used these arguments |
assert_called_once_with(*args, **kwargs) |
Called exactly once with these arguments |
assert_has_calls(calls, any_order=False) |
All specified calls were made (optionally in any order) |
call_count |
Integer — total number of times the mock was called |
call_args |
The arguments of the most recent call as a call object |
call_args_list |
List of call objects for every invocation |
call object
call objects for every invocation
assert_called_once() and assert_called_once_with() are distinct methods. assert_called_once() — without arguments — was added in Python 3.6 and simply asserts that the mock was called exactly one time. A common earlier mistake was writing mock.assert_called_once() on Python versions before 3.6 and having it silently pass with no actual assertion, because plain Mock objects accept any attribute access as a new child mock. Since Python 3.5, accessing an attribute whose name starts with assert, assret, asert, aseert, or assrt on a non-autospecced mock raises AttributeError by default (when unsafe=False), which surfaces many of these typos at test runtime rather than silently passing them. The full list of protected prefixes — confirmed in the Python 3 standard library documentation — is: assert, assret, asert, aseert, and assrt.
mock.return_value = 'A' and mock.side_effect = ['B', 'C']. What does the first call to the mock return?autospec — making mocks enforce the real interface
By default, a MagicMock accepts any call with any arguments — a behavior rooted in duck typing principles — because it does not know what the real object's signature looks like. This means your tests can continue to pass after you refactor the real API in a breaking way — the mock never notices. Passing autospec=True to patch tells it to build the mock by inspecting the real object's attributes and method signatures. Calls that do not match the real signature raise TypeError immediately, just as calling the real object with wrong arguments would:
# notifier.py
class AlertService:
def send(self, message: str, priority: int = 1) -> bool:
# Real implementation would call an external service
return True
# test_notifier_autospec.py
import unittest
from unittest.mock import patch, MagicMock
from notifier import AlertService
class TestAlertServiceAutospec(unittest.TestCase):
@patch('notifier.AlertService', autospec=True)
def test_send_called_with_correct_args(self, MockAlertService: MagicMock) -> None:
instance = MockAlertService.return_value
instance.send.return_value = True
service = MockAlertService()
result = service.send("Disk usage critical", priority=2)
instance.send.assert_called_once_with("Disk usage critical", priority=2)
self.assertTrue(result)
@patch('notifier.AlertService', autospec=True)
def test_wrong_argument_raises_type_error(self, MockAlertService: MagicMock) -> None:
instance = MockAlertService.return_value
# send() does not accept a 'severity' keyword argument.
# Without autospec this would silently pass.
# With autospec it raises TypeError immediately.
with self.assertRaises(TypeError):
instance.send("High CPU", severity=5)
if __name__ == '__main__':
unittest.main()
autospec also catches misspelled assertion method names. Without it, writing mock.assert_called_once() when you meant mock.assert_called_once_with(args) silently passes because the mock just creates a new child mock for the unknown attribute. With autospec=True, only methods that exist on the real object are accessible on the mock.
There is one known limitation of autospec: it inspects the object at patcher creation time using getattr. If your class overrides __getattribute__, creating an autospecced mock may trigger those side effects during test setup. For objects with large numbers of attributes, autospeccing adds a small but measurable overhead to test collection time. Use it where interface accuracy matters most — public APIs, third-party client classes, and any module boundary that is likely to change.
Patching async functions with AsyncMock
When the target is a coroutine function, patch automatically installs an AsyncMock rather than a MagicMock (since Python 3.8). AsyncMock is awaitable and records the same call information. You configure return_value and side_effect in exactly the same way:
# async_weather.py
import aiohttp
async def get_temperature(city: str) -> float:
async with aiohttp.ClientSession() as session:
async with session.get(f'https://api.weather.example.com/{city}') as resp:
data = await resp.json()
return data['temp_c']
# test_async_weather.py
import unittest
from unittest.mock import patch, AsyncMock, MagicMock
import async_weather
class TestGetTemperature(unittest.IsolatedAsyncioTestCase):
@patch('async_weather.aiohttp.ClientSession')
async def test_returns_temperature(self, MockSession: MagicMock) -> None:
# Mock the innermost response: resp.json() is a coroutine.
mock_response = AsyncMock()
mock_response.json.return_value = {'temp_c': 18.5}
# async with session.get(...) as resp → __aenter__ yields mock_response
mock_request_cm = MagicMock()
mock_request_cm.__aenter__ = AsyncMock(return_value=mock_response)
mock_request_cm.__aexit__ = AsyncMock(return_value=False)
mock_session = MagicMock()
mock_session.get.return_value = mock_request_cm
# async with aiohttp.ClientSession() as session → __aenter__ yields mock_session
mock_session_cm = MagicMock()
mock_session_cm.__aenter__ = AsyncMock(return_value=mock_session)
mock_session_cm.__aexit__ = AsyncMock(return_value=False)
MockSession.return_value = mock_session_cm
temp = await async_weather.get_temperature('London')
self.assertEqual(temp, 18.5)
if __name__ == '__main__':
unittest.main()
mock_open — patching file I/O
unittest.mock.mock_open is a helper that returns a pre-configured mock suitable for replacing Python's built-in open. It handles the context manager protocol and the read(), readline(), and iteration interfaces so you do not need to wire those up yourself. Note that full iteration support — the ability to use mock_open's read_data in a for loop — was added in Python 3.7.1 via __iter__(). On Python 3.7.0 and earlier, looping directly over the mock file object did not consume read_data; only read() and readline() did:
# text_utils.py
# NOTE: avoid naming this file parser.py — that shadows the stdlib parser module
# removed in Python 3.12, which can cause confusing ImportErrors.
def count_lines(path: str) -> int:
with open(path, 'r') as f:
return sum(1 for _ in f)
# test_text_utils.py
import unittest
from unittest.mock import patch, mock_open
import text_utils
FAKE_FILE_CONTENT = "line one\nline two\nline three\n"
class TestCountLines(unittest.TestCase):
def test_counts_three_lines(self) -> None:
m = mock_open(read_data=FAKE_FILE_CONTENT)
with patch('builtins.open', m):
count = text_utils.count_lines('/fake/path/file.txt')
self.assertEqual(count, 3)
m.assert_called_once_with('/fake/path/file.txt', 'r')
if __name__ == '__main__':
unittest.main()
Additional Parameters: wraps and new_callable
wraps — spy on a real callable without replacing it
The wraps parameter lets you install a mock that delegates every actual call to a real callable, while still recording call information. This is known as a spy: the real function executes and returns its actual result, but the mock wrapper intercepts the call so you can assert on arguments and call count afterward.
This is distinct from autospec=True. With autospec, the real function never runs; with wraps, it always does. Use wraps when you need to verify call behavior against a function whose real side effects are acceptable or necessary in the test environment:
# formatter.py
def format_currency(amount: float, symbol: str = '$') -> str:
return f"{symbol}{amount:,.2f}"
# test_formatter_spy.py
import unittest
from unittest.mock import patch, MagicMock
import formatter
class TestFormatCurrencySpy(unittest.TestCase):
def test_called_with_correct_args(self) -> None:
# wraps= means the real function still runs; the mock just observes.
with patch('formatter.format_currency',
wraps=formatter.format_currency) as spy:
result = formatter.format_currency(1234.5)
# The real function returned the correct string.
self.assertEqual(result, '$1,234.50')
# The spy recorded the call.
spy.assert_called_once_with(1234.5)
if __name__ == '__main__':
unittest.main()
new_callable — substituting a different mock class
By default, patch() installs a MagicMock. The new_callable parameter lets you substitute a different class. The most common reason to do this is patching a property — Python properties are descriptors, not plain attributes, and replacing them with MagicMock does not wire up the descriptor protocol. PropertyMock is the correct replacement:
# server.py
class Server:
@property
def is_online(self) -> bool:
# Real implementation would check a network socket
return True
# test_server.py
import unittest
from unittest.mock import patch, PropertyMock
from server import Server
class TestServer(unittest.TestCase):
@patch.object(Server, 'is_online', new_callable=PropertyMock)
def test_offline_branch(self, mock_is_online: PropertyMock) -> None:
mock_is_online.return_value = False
s = Server()
self.assertFalse(s.is_online)
mock_is_online.assert_called_once()
if __name__ == '__main__':
unittest.main()
Since Python 3.8, patch() automatically installs an AsyncMock when the target is detected as a coroutine function, so new_callable=AsyncMock is rarely needed for async targets on 3.8+. You would only specify it explicitly on older codebases or when patching a non-coroutine that you want to behave as one for testing purposes.
patch.multiple — patching several targets in one call
patch.multiple() accepts a target module and any number of keyword arguments, each naming an attribute to patch in that module. Unlike stacking individual @patch decorators, patch.multiple does not inject mock arguments into the test method unless you pass DEFAULT as the value. This makes it useful for patching several side-effect-prone attributes where you need them replaced but do not need to assert on them individually:
# test_multiple.py
import unittest
from unittest.mock import patch, DEFAULT, MagicMock
import os
class TestMultiplePatch(unittest.TestCase):
# Patch os.getcwd and os.listdir in one decorator call.
# Passing DEFAULT tells patch.multiple to create a MagicMock and
# inject it as a keyword argument named after the attribute.
@patch.multiple('os', getcwd=DEFAULT, listdir=DEFAULT)
def test_directory_listing(self, getcwd: MagicMock, listdir: MagicMock) -> None:
getcwd.return_value = '/tmp/project'
listdir.return_value = ['README.md', 'main.py']
cwd = os.getcwd()
files = os.listdir(cwd)
self.assertEqual(cwd, '/tmp/project')
self.assertIn('main.py', files)
getcwd.assert_called_once()
if __name__ == '__main__':
unittest.main()
ThreadingMock — testing multithreaded call behavior (Python 3.13+)
Python 3.13 added ThreadingMock to unittest.mock. It is a version of MagicMock designed specifically for multithreaded tests, where the normal pattern of asserting immediately after a call does not work because the call you want to verify may not have happened yet — it is happening concurrently on another thread.
ThreadingMock provides wait_until_called() and wait_until_any_call_with() methods that block the test thread until the mock is called — or until an optional timeout expires, at which point they raise AssertionError. This eliminates the need for fragile time.sleep() calls or manual threading.Event coordination in tests that need to verify cross-thread interactions:
# worker.py
import threading
def run_in_thread(callback, *args):
"""Runs callback in a daemon thread and returns the thread."""
t = threading.Thread(target=callback, args=args, daemon=True)
t.start()
return t
# test_worker.py — requires Python 3.13+
import unittest
import threading
from unittest.mock import patch, ThreadingMock
import worker
class TestRunInThread(unittest.TestCase):
def test_callback_called_on_background_thread(self) -> None:
# ThreadingMock blocks this test thread until the mock is called,
# rather than asserting immediately (which would be a race condition).
mock_callback = ThreadingMock()
t = worker.run_in_thread(mock_callback, 'payload')
# wait_until_called() blocks until the mock is invoked.
# Pass timeout= to fail rather than hang if the call never comes.
mock_callback.wait_until_called(timeout=2)
t.join()
mock_callback.assert_called_once_with('payload')
def test_specific_args_called_on_background_thread(self) -> None:
mock_callback = ThreadingMock()
t = worker.run_in_thread(mock_callback, 'event_name', 42)
# wait_until_any_call_with() blocks until a call matching
# the specified arguments arrives.
mock_callback.wait_until_any_call_with('event_name', 42, timeout=2)
t.join()
if __name__ == '__main__':
unittest.main()
ThreadingMock is only available in Python 3.13 and later. For earlier versions, the closest equivalent is to coordinate with a threading.Event: have the mock's side_effect set an event, then call event.wait(timeout=N) in the test. ThreadingMock internalizes this pattern so you no longer need to wire it manually. The global default timeout for all ThreadingMock instances can be set via ThreadingMock.DEFAULT_TIMEOUT.
Three Questions the Patch Documentation Does Not Answer Clearly
create_autospec() — autospec without a patch target
autospec=True inside a patch() call builds the spec automatically from the object being replaced. But there are scenarios where you need a spec'd mock without patching anything — for example, when constructing a dependency in a test's setUp method, or when building a mock to pass directly as an argument. create_autospec() handles this. It takes a real object or class and returns a MagicMock whose attributes, methods, and call signatures mirror those of the original:
# storage.py
class BlobStorage:
def upload(self, key: str, data: bytes, content_type: str = "application/octet-stream") -> str:
# Real implementation writes to cloud storage
return f"https://storage.example.com/{key}"
def delete(self, key: str) -> None:
pass
# test_storage_spec.py
import unittest
from unittest.mock import create_autospec
from storage import BlobStorage
class TestWithCreateAutospec(unittest.TestCase):
def setUp(self) -> None:
# create_autospec() builds a mock from the real class signature.
# No patch() needed — we pass this mock directly to the code under test.
self.mock_storage = create_autospec(BlobStorage, instance=True)
def test_upload_called_with_correct_signature(self) -> None:
self.mock_storage.upload.return_value = "https://storage.example.com/report.pdf"
result = self.mock_storage.upload("report.pdf", b"data", content_type="application/pdf")
self.assertEqual(result, "https://storage.example.com/report.pdf")
self.mock_storage.upload.assert_called_once_with(
"report.pdf", b"data", content_type="application/pdf"
)
def test_wrong_signature_raises(self) -> None:
# autospec enforces the real signature — extra kwargs raise TypeError
with self.assertRaises(TypeError):
self.mock_storage.upload("key.bin", b"data", nonexistent_param=True)
if __name__ == "__main__":
unittest.main()
Pass instance=True when you want the spec'd mock to behave as an instance of the class rather than as the class itself. Without it, create_autospec(BlobStorage) produces a mock that behaves like the class — callable, returning an instance — which is correct when you are patching the class constructor but wrong when you are substituting an already-instantiated object.
autospec=True and create_autospec() build the spec by calling dir() on the real object. Attributes set at runtime in __init__ rather than declared at class level — and attributes injected by frameworks like Django or SQLAlchemy — are often invisible to dir() at spec-build time. Accessing those attributes on the autospecced mock raises AttributeError, even though the real object has them. In those cases, drop back to a plain MagicMock and configure only the attributes you specifically need to control.
spec vs autospec — what is the difference?
Both spec and autospec constrain what a mock will accept, but they do so at different levels of depth. Understanding the distinction matters when you are choosing between them.
spec restricts attribute access: the mock will raise AttributeError if you access a name that does not exist on the real object. It says nothing about how methods should be called — you can pass any number of arguments to a spec'd method and the mock will not complain. spec is a shallow constraint.
autospec=True (or create_autospec()) goes deeper: it enforces the actual call signature of every method, not just whether the attribute exists. A method declared as def send(self, message, priority=1) will raise TypeError if called with wrong argument count or unknown keyword arguments on an autospecced mock, exactly as the real method would. autospec is a deep constraint:
# comparing spec= vs autospec=True
import unittest
from unittest.mock import MagicMock, create_autospec
class Notifier:
def send(self, message: str, priority: int = 1) -> bool:
return True
# spec= constrains attribute access only — wrong args still silently pass
spec_mock = MagicMock(spec=Notifier)
spec_mock.send("hello", priority=1, unknown_kwarg="oops") # no error raised
# autospec enforces the real signature — wrong args raise TypeError immediately
auto_mock = create_autospec(Notifier, instance=True)
try:
auto_mock.send("hello", priority=1, unknown_kwarg="oops")
except TypeError as e:
print(f"autospec caught bad kwarg: {e}")
# Output: autospec caught bad kwarg: send() got an unexpected keyword argument 'unknown_kwarg'
The practical guideline is: use autospec=True by default in new test code. Use plain spec= only in the narrow case where you specifically need attribute restriction without signature enforcement — for example, when patching an interface that uses *args, **kwargs throughout and signature checking would always pass.
The assert_called_once typo trap
One of the longest-standing silent failure modes in Python testing is writing mock.assert_called_once() as a standalone statement — with no parentheses on a method that does not exist. Before Python 3.5, a plain MagicMock accepted attribute access on any name and returned a new child mock. So mock.assert_called_once without () silently evaluated to a truthy child mock and the test passed regardless of whether the mock was ever called. Even with parentheses, assert_called_once() is a different method from assert_called_once_with() — the former checks only call count; the latter checks both count and arguments. These are distinct methods and both are valid, but they are frequently confused:
# assert_called_once vs assert_called_once_with — illustrated
import unittest
from unittest.mock import MagicMock
class TestAssertionTrap(unittest.TestCase):
def test_assert_called_once_checks_count_only(self) -> None:
mock_fn = MagicMock()
mock_fn("wrong_arg")
# This passes — called exactly once, regardless of arguments.
mock_fn.assert_called_once()
# This would FAIL — called once but not with the expected argument.
# mock_fn.assert_called_once_with("expected_arg") # raises AssertionError
def test_assert_called_once_with_checks_both(self) -> None:
mock_fn = MagicMock()
mock_fn("correct_arg")
# This passes — called once AND with the right argument.
mock_fn.assert_called_once_with("correct_arg")
def test_misspelled_assert_raises_attribute_error(self) -> None:
mock_fn = MagicMock()
mock_fn("data")
# Since Python 3.5, accessing a name starting with "assert" that does
# not exist on Mock raises AttributeError rather than silently returning
# a child mock. This surfaces the typo at test runtime.
with self.assertRaises(AttributeError):
mock_fn.assert_called_onec_with("data") # typo: 'onec'
if __name__ == "__main__":
unittest.main()
Since Python 3.5, the mock library raises AttributeError when you access an attribute whose name begins with assert, assret, asert, aseert, or assrt but is not a real assertion method. This catches the most common typos at test runtime rather than silently passing them. The defense is to use autospec=True in addition — an autospecced mock only exposes assertion methods that exist on the real object, eliminating the entire category of fabricated method names.
patch('builtins.X') — patching built-in functions
Built-in functions like open, input, print, and len live in the builtins module. Patching them follows exactly the same where-it-is-looked-up rule as any other name — but because every Python module implicitly imports from builtins, the target is simply 'builtins.open' regardless of which module you are testing. You do not need to qualify it with your module name:
# cli.py
def prompt_for_name() -> str:
name = input("Enter your name: ")
return name.strip().title()
# test_cli.py
import unittest
from unittest.mock import patch
import cli
class TestPromptForName(unittest.TestCase):
@patch("builtins.input", return_value=" alice smith ")
def test_strips_and_titles(self, mock_input: object) -> None:
result = cli.prompt_for_name()
self.assertEqual(result, "Alice Smith")
mock_input.assert_called_once_with("Enter your name: ")
@patch("builtins.print")
def test_print_called(self, mock_print: object) -> None:
# Patching print lets you assert on what your code outputs
# without capturing stdout.
print("hello from test")
mock_print.assert_called_once_with("hello from test")
if __name__ == "__main__":
unittest.main()
Since Python 3.5, patch() automatically handles builtins without requiring create=True. The create=True parameter is for a different scenario: patching an attribute that does not yet exist on the target object at test time — for example, an attribute your production code adds dynamically at runtime. Use it sparingly; enabling create=True means you can write tests against attributes that do not actually exist, which can mask bugs rather than surface them. The Python documentation notes this explicitly as a deliberate off-by-default safeguard.
Key Takeaways
- Patch where the name is looked up, not where it is defined. The target string must point to the attribute in the namespace that the code under test will access at runtime. A
from x import yimport creates a local binding in the importing module; patch that binding, notx.yin the original module. - Use
autospec=Trueto protect against interface drift. A plainMagicMockaccepts any call regardless of argument count or attribute name.autospec=Truebuilds the mock from the real object's signature so that breaking refactors are caught by tests rather than silently passing. - Use
create_autospec()when you need a spec'd mock without a patch target. When constructing a dependency directly insetUpor passing a mock as an argument rather than patching a module,create_autospec(MyClass, instance=True)gives you the same signature enforcement asautospec=Truewithout requiring a dotted string target path. - Prefer
autospecover plainspec.spec=restricts attribute access only;autospec=Trueadditionally enforces method call signatures. Wrong keyword arguments and incorrect argument counts slip pastspec=silently. - Prefer
side_effectfor exception simulation and sequential return values. Setside_effectto an exception class to simulate failures, to an iterable to return different values on successive calls, or to a callable when the response depends on the arguments received.side_effecttakes precedence overreturn_valuewhen both are set. - Use
wrapswhen you need real behavior plus call observability. Unlike replacing a function entirely,wrapsdelegates to the real callable while the mock records the interaction — a targeted spy that does not change program output. - Always register cleanup with
addCleanupwhen starting patchers manually. When usingpatcher.start()insetUp, callself.addCleanup(patcher.stop)rather than relying ontearDown. Cleanup functions run even whensetUpraises midway, preventing leaked patches from contaminating subsequent tests. - Distinguish
assert_called_once()fromassert_called_once_with(). The former verifies only call count; the latter verifies both count and arguments. They are separate methods. Useautospec=Trueas an additional safeguard — it prevents attribute access on non-existent assertion method names that would otherwise silently pass. - Patch builtins at
builtins.X, not in the calling module. Built-in functions likeopen,input, andprintare resolved from thebuiltinsnamespace, so the patch target is always'builtins.open'— no module prefix needed. Since Python 3.5,create=Trueis not required for builtins. - Use
ThreadingMock(Python 3.13+) when the call under test happens on a background thread. Standard mock assertions are immediate; if a callback fires concurrently, the assertion races the call.ThreadingMock.wait_until_called(timeout=N)blocks the test thread until the mock is invoked or the timeout expires, making concurrent call assertions deterministic withouttime.sleep().
Controlled isolation through @unittest.mock.patch is what separates a test that verifies your logic from a test that verifies your infrastructure. Once you internalize the lookup rule, the decorator stacking order, and the return_value/side_effect distinction, the entire module becomes a straightforward and powerful tool for writing deterministic, fast, and dependency-free unit tests.
How to Use Python @unittest.mock.patch
- Import patch from unittest.mock. Add
from unittest.mock import patchat the top of your test file. Thepatchfunction has been part of Python's standard library since version 3.3 and requires no additional installation. - Identify the correct patch target. Determine the dotted string path to the object as it is used inside the module under test — not where it is defined. The format is
'package.module.attribute'. Always patch where the name is looked up at runtime, not where the object originates. - Apply @patch as a decorator and accept the mock argument. Decorate your test method with
@patch('your.target.path'). Add an extra parameter to your test function — it receives theMagicMockinstance that replaced the real object for the duration of the test. - Configure return_value or side_effect. Set
mock.return_valueto control what the mocked callable returns. Setmock.side_effectto raise an exception, cycle through multiple return values, or delegate to a callable.side_effecttakes precedence overreturn_valuewhen both are set. - Assert call behavior after executing the code under test. Use
assert_called_once(),assert_called_with(),assert_called_once_with(),call_count, andcall_argsto verify the mock was invoked correctly. Addautospec=Trueto catch interface drift between your mocks and the real objects they replace. - Use
ThreadingMockfor concurrent call assertions (Python 3.13+). When the call you want to assert fires on a background thread, substituteThreadingMockforMagicMock. Callwait_until_called(timeout=N)after launching the thread to block the test until the mock is invoked, making the assertion deterministic.
Frequently Asked Questions
What does @unittest.mock.patch actually replace?
@unittest.mock.patch temporarily replaces a named attribute in a module's namespace with a MagicMock instance, or another object you specify via the new argument. According to the Python standard library documentation, the replacement is restored once the test ends — even when an exception is raised. The mechanism is straightforward: patch uses getattr to save the original value, setattr to install the replacement, and setattr again at cleanup to restore it.
Why do I need to patch where the object is used, not where it is defined?
When a module imports a name with from module import name, it creates a local binding to that name in its own namespace. Patching the source module replaces the object there, but the local binding in the module under test already holds a direct reference to the original object — patching the source has no effect on it. The Python documentation makes this a first-class rule: the correct namespace to target is the one the code under test resolves names from at runtime, not where those names were originally defined. See: Python docs — unittest.mock quick guide.
What is the difference between patch(), patch.object(), and patch.dict()?
patch() takes a dotted string path and patches the named attribute in that module namespace. patch.object() takes a live Python object and a string attribute name — it is useful when you already have a reference to the object and want your test to fail at load time if the attribute does not exist, rather than at runtime. patch.dict() patches a dictionary for the duration of the test, merging in new keys and restoring the original state on exit; it is the standard approach for controlling os.environ without touching it directly.
When should I use autospec=True?
Use autospec=True whenever you want the mock to enforce the real object's method signatures and attribute interface. Without it, a plain MagicMock accepts any call regardless of argument count or attribute name, which means tests can pass silently after a breaking API refactor. The Python standard library documentation explains that auto-speccing inspects the real object and builds a mock whose methods only accept the same arguments as their real counterparts — so incorrect calls raise TypeError immediately, the same way they would against production code.
What is the difference between return_value and side_effect?
return_value sets a fixed value returned every time the mock is called. side_effect is more flexible: it can be an exception class or instance to raise on call, an iterable that yields successive values (raising any exception objects in the sequence rather than returning them), or a callable that receives the same arguments and computes a response. When both are set, the Python documentation confirms that side_effect takes precedence over return_value.
How do I patch multiple objects in a single test?
Stack multiple @patch decorators above the test method. Decorators are applied bottom-up, so the decorator closest to the def line corresponds to the first extra parameter in the method signature; the topmost decorator corresponds to the last. Alternatively, use patch.multiple() to patch several attributes of the same module in one decorator call, passing DEFAULT as the value for each attribute you want injected as a keyword argument.
What does the wraps parameter do?
The wraps parameter installs a mock that delegates every call to a real callable, while still recording it. The real function runs and returns its actual result; the mock wrapper intercepts the call so you can assert on arguments and call count afterward. This is a spy pattern: use it when you need to verify that a real function was called correctly without suppressing its side effects. It is the opposite of autospec, where the real function never runs.
What is new_callable used for in patch()?
new_callable lets you substitute a different mock class instead of the default MagicMock. The most common use is patching a property — Python properties are descriptors, and a plain MagicMock does not wire up the descriptor protocol correctly. Using new_callable=PropertyMock with patch.object() produces a mock that behaves as a property. Since Python 3.8, patch() automatically uses AsyncMock for coroutine function targets, so explicit new_callable=AsyncMock is rarely needed on modern Python.
What is ThreadingMock and when do I need it?
ThreadingMock, added in Python 3.13, is a MagicMock subclass designed for testing code that runs callbacks or triggers calls on background threads. Standard mocks fail in this scenario because the call you want to assert on may not have happened yet when the assertion runs. ThreadingMock solves this with wait_until_called(timeout=N) and wait_until_any_call_with(..., timeout=N), which block the test thread until the call arrives — or raise AssertionError if the timeout expires. This eliminates the need for time.sleep() or manual threading.Event coordination in concurrent tests.
What is the difference between spec and autospec?
spec= restricts attribute access: accessing a name that does not exist on the real object raises AttributeError. It does not enforce how methods are called — you can pass any arguments to a spec'd method and no error is raised. autospec=True goes further: it enforces the actual call signature of every method, so wrong argument counts and invalid keyword arguments raise TypeError immediately. In most test code, autospec=True is the stronger and more useful option. Use plain spec= only when you need attribute restriction without signature checking — for instance, when the real object's methods accept arbitrary arguments.
When should I use create_autospec() instead of autospec=True in patch()?
Use create_autospec(MyClass, instance=True) when you need a spec-enforced mock that you are constructing directly — for example, in a test's setUp method or when passing a mock as an argument to the system under test rather than patching a module. autospec=True inside patch() applies the same enforcement but requires a dotted-path target string. Both produce mocks with the same signature constraints; the difference is only in how the mock is created. When you do not have a patch target — or when the mock needs to outlive a single test method — create_autospec() is the right tool.
How do I patch builtins like open, input, and print?
Built-in functions are resolved from the builtins namespace, so the target is always 'builtins.open', 'builtins.input', or 'builtins.print' regardless of which module you are testing. Unlike regular imports, you do not qualify the path with your module name. For file I/O, combine patch('builtins.open') with mock_open(read_data=...) to get a pre-configured mock that handles the context manager protocol and read interface automatically. Since Python 3.5, patching builtins does not require the create=True flag.
Sources and References
- Python Software Foundation. unittest.mock — mock object library. Python 3 Standard Library Documentation. Retrieved March 2026.
- Python Software Foundation. unittest.mock — getting started. Python 3 Standard Library Documentation. Retrieved March 2026.
- Python Software Foundation. What's New in Python 3.8. Python 3 Documentation.
AsyncMockandIsolatedAsyncioTestCaseadded in 3.8. Retrieved March 2026. - Python Software Foundation. What's New in Python 3.13. Python 3 Documentation.
ThreadingMockadded in 3.13. Retrieved March 2026. - PyPI. mock — Rolling backport of unittest.mock. mock 5.2.0. March 2025.
- Meszaros, Gerard. xUnit Test Patterns: Refactoring Test Code. Addison-Wesley, 2007. ISBN 978-0-13-149505-0. Source of the canonical test doubles taxonomy: dummy, fake, stub, spy, and mock.