Quick answer: Mock a Python context manager by configuring __enter__ to return the resource used inside the with block and __exit__ to represent cleanup and exception behavior. Patch the name where the code under test looks it up.

A Python context manager is any object that works inside a with block. It enters before the block body runs and exits afterward, even when an exception occurs. Tests often need to replace that behavior so file handles, database sessions, locks, clients, or temporary resources do not touch the real system.
The standard unittest.mock module can mock context managers directly. The important methods are __enter__ and __exit__. __enter__ controls the object bound after as, while __exit__ controls cleanup and whether exceptions are suppressed.
A good test should make both parts explicit. The setup should show what the code receives inside the with block, and the assertions should show that the block was entered, used, and exited as expected. This keeps context-manager tests readable instead of hiding behavior inside a large mock setup.
Primary references include the unittest.mock documentation, MagicMock magic method support, patch documentation, mock_open documentation, and the with statement reference.
Mock A Basic Context Manager
Use MagicMock when you need magic methods such as __enter__ and __exit__.
from unittest.mock import MagicMock
resource = MagicMock()
resource.read.return_value = "payload"
manager = MagicMock()
manager.__enter__.return_value = resource
manager.__exit__.return_value = False
with manager as opened:
result = opened.read()
print(result)
manager.__enter__.assert_called_once()
The object returned by __enter__ becomes opened. That is the object your production code usually reads from or calls.
Configure methods on the returned object, not on the manager itself, when the code inside the block calls those methods. This mirrors real context managers, where entering a resource often returns a handle or client.
Patch A Context Manager Factory
When code calls a factory that returns a context manager, patch the factory at the lookup path used by the code under test.
from unittest.mock import MagicMock, patch
def load_text(factory):
with factory("notes.txt") as handle:
return handle.read()
mock_handle = MagicMock()
mock_handle.read.return_value = "hello"
mock_manager = MagicMock()
mock_manager.__enter__.return_value = mock_handle
with patch("__main__.open", return_value=mock_manager) as mocked_open:
text = load_text(open)
print(text)
mocked_open.assert_called_once_with("notes.txt")
The patch target depends on where the name is looked up. Patching the wrong module is one of the most common causes of tests that do not intercept anything.
Use the import path that the code under test actually uses. If a module did from pathlib import Path, patch that module’s Path name rather than the original library name.
Use mock_open For File Reads
For normal file reads, mock_open() is simpler than building __enter__ by hand.
from unittest.mock import mock_open, patch
def read_config():
with open("config.txt", encoding="utf-8") as handle:
return handle.read().strip()
fake_open = mock_open(read_data="mode=test\n")
with patch("builtins.open", fake_open):
config = read_config()
print(config)
fake_open.assert_called_once_with("config.txt", encoding="utf-8")
This keeps the test focused on how the file is used, without creating a real file on disk.

Check Cleanup Calls
The with statement should call __exit__ after the block finishes.
from unittest.mock import MagicMock
manager = MagicMock()
manager.__enter__.return_value = "ready"
manager.__exit__.return_value = False
with manager as status:
print(status)
manager.__exit__.assert_called_once()
print(manager.__exit__.call_args)
Asserting __exit__ is useful when cleanup is the behavior you care about, such as closing sessions or releasing locks.
The call arguments to __exit__ also show whether an exception was active when the block ended. That can be helpful when testing cleanup that must run during failure paths.
Test Exception Flow
If __exit__ returns False, exceptions propagate. If it returns True, the context manager suppresses them.
from unittest.mock import MagicMock
manager = MagicMock()
manager.__enter__.return_value = "inside"
manager.__exit__.return_value = True
with manager:
raise RuntimeError("hidden by __exit__")
print("continued")
manager.__exit__.assert_called_once()
Most mocks should return False unless the real context manager intentionally suppresses exceptions. Returning True can hide bugs in tests.
If the real context manager suppresses a specific exception, add a focused test for that behavior. Otherwise, keep propagation as the default so failures remain visible.

Wrap Mock Setup In A Helper
A helper keeps repeated mock setup readable when several tests need the same context manager shape.
from unittest.mock import MagicMock
def make_context_manager(returned):
manager = MagicMock()
manager.__enter__.return_value = returned
manager.__exit__.return_value = False
return manager
client = MagicMock()
client.fetch.return_value = {"ok": True}
manager = make_context_manager(client)
with manager as active_client:
data = active_client.fetch()
print(data)
This keeps the intent clear: the helper builds the context manager, and the test configures the object used inside the block.
Helpers are useful when several tests need the same context-manager shape. Keep them small so each test can still show the important returned object and assertions.
Practical Guidance
Use MagicMock for custom context managers because it supports magic methods. Use mock_open() for straightforward file reads. Use patch() as a context manager so the replacement is active only inside the test block.
Assert both the factory call and the object used inside the with block. That confirms the code opened the resource you expected and interacted with the returned object correctly.
Keep __exit__.return_value explicit. A test should say whether exceptions are expected to propagate or be suppressed. Most resource managers should not swallow exceptions silently.
The safest workflow is to patch where the name is looked up, set __enter__.return_value to the object the code should use, and verify cleanup through __exit__ or the returned object’s close-style method.
When a mock context manager becomes hard to understand, consider using a tiny fake class instead. A fake can be clearer when the behavior has state, several methods, or non-trivial cleanup rules.
Model The with Protocol
The with statement calls __enter__ before the block and __exit__ afterward, including when the block raises. A mock should represent those lifecycle boundaries rather than only replacing one method.

Use MagicMock
MagicMock includes common magic methods, making it suitable for context-manager protocols. Set __enter__.return_value to the fake resource and keep the fake resource’s behavior focused on the test.
Patch At The Lookup Site
If a module imported a class into its own namespace, patch that local name. Patching the original definition after the import may leave the code under test using the real object.

Test Cleanup And Exceptions
Configure __exit__ to return false when exceptions should propagate or true only when suppression is part of the contract. Assert calls and arguments rather than assuming cleanup occurred.
Prefer A Small Fake When Clearer
A tiny real context-manager fake can be easier to read when lifecycle state matters. Use mocks for interaction assertions and fakes for meaningful resource behavior.
Test The Boundary
Test successful entry, cleanup, entry failure, block exceptions, suppressed exceptions, multiple uses, and the exact resource returned. Reset mocks between scenarios to avoid call leakage.
The official unittest.mock documentation covers magic methods and patching. Related Python Pool references include testing and diagnostics.
For reliable mocked workflows, compare test isolation patterns, diagnostic logging, and configuration lookups before asserting context-manager behavior.
Frequently Asked Questions
How do I mock a context manager in Python?
Use MagicMock or a context-manager mock and configure its __enter__ return value and __exit__ behavior.
Where should I patch a context manager?
Patch the name where the code under test looks it up, not necessarily where the class was originally defined.
How do I make the with block receive a fake resource?
Set mock_context.__enter__.return_value to the object the block should use.
How do I test exceptions in a mocked context manager?
Configure __exit__ with the intended return value and assert whether the exception is suppressed or propagated according to the contract.