Rolling backport of unittest.mock for all Pythons
—
Patching allows temporary replacement of objects with mocks during testing. The mock library provides several patching mechanisms that work as context managers, decorators, or manual start/stop operations.
The main patching function that replaces objects with mocks temporarily.
def patch(
target,
new=None,
spec=None,
create=False,
spec_set=None,
autospec=None,
new_callable=None,
*,
unsafe=False,
**kwargs
):
"""
Replace target object with a mock.
Parameters:
- target: String specifying the target to patch (e.g., 'module.ClassName')
- new: Object to replace target with (defaults to MagicMock)
- spec: Specification for the mock
- create: Create target if it doesn't exist
- spec_set: More restrictive spec
- autospec: Create mock with automatic spec
- new_callable: Alternative to new, called to create replacement
- unsafe: Allow access to dangerous attributes
- **kwargs: Additional arguments passed to mock constructor
Returns:
Mock object (when used as context manager or started manually)
"""Patch a named attribute on an object.
def patch.object(
target,
attribute,
new=None,
spec=None,
create=False,
spec_set=None,
autospec=None,
new_callable=None,
**kwargs
):
"""
Patch a named attribute on an object.
Parameters:
- target: Object to patch
- attribute: String name of attribute to patch
- new: Replacement object (defaults to MagicMock)
- spec: Specification for the mock
- create: Create attribute if it doesn't exist
- spec_set: More restrictive spec
- autospec: Create mock with automatic spec
- new_callable: Alternative to new, called to create replacement
- **kwargs: Additional arguments passed to mock constructor
Returns:
Mock object (when used as context manager or started manually)
"""Patch multiple attributes on a target object simultaneously.
def patch.multiple(
target,
spec=None,
create=False,
spec_set=None,
autospec=None,
new_callable=None,
**kwargs
):
"""
Patch multiple attributes on a target object.
Parameters:
- target: Object or string specifying target to patch
- spec: Specification for the mocks
- create: Create attributes if they don't exist
- spec_set: More restrictive spec
- autospec: Create mocks with automatic spec
- new_callable: Alternative callable for creating mocks
- **kwargs: attribute_name=replacement pairs
Returns:
Dictionary of attribute names to mock objects
"""Context manager for patching dictionaries, including environment variables and module-level dictionaries.
class patch.dict:
def __init__(
self,
in_dict,
values=(),
clear=False,
**keywds
):
"""
Patch a dictionary or dictionary-like object.
Parameters:
- in_dict: Dictionary to patch or string specifying target
- values: Dictionary or iterable of (key, value) pairs to set
- clear: Clear dictionary before setting values
- **keywds: Keyword arguments for values to set
"""
def __enter__(self):
"""Enter context manager, apply patches."""
def __exit__(self, *args):
"""Exit context manager, restore original values."""
def start(self):
"""Start patching manually."""
def stop(self):
"""Stop patching manually."""All patch objects (returned by patch, patch.object, patch.multiple) support manual start/stop control:
class _patch:
def start(self):
"""
Start patching manually.
Returns:
Mock object that replaces the target
"""
def stop(self):
"""
Stop patching manually.
Restores original object and cleans up.
"""
def __enter__(self):
"""Context manager entry - equivalent to start()."""
def __exit__(self, *args):
"""Context manager exit - equivalent to stop()."""def stop_all():
"""
Stop all active patches that were started with start().
This function stops all patches that are currently active
from manual start() calls. Does not affect context manager
or decorator patches.
"""from mock import patch
# Basic patching
with patch('module.function') as mock_func:
mock_func.return_value = 'mocked'
# Code using module.function() will get 'mocked'
# Object attribute patching
with patch.object(obj, 'method') as mock_method:
mock_method.return_value = 'result'
# obj.method() will return 'result'
# Multiple patching
with patch.multiple('module', func1='mock1', func2='mock2') as mocks:
# module.func1 and module.func2 are now mocked
# mocks is {'func1': mock1, 'func2': mock2}from mock import patch
@patch('module.function')
def test_something(mock_func):
mock_func.return_value = 42
# Test code here
@patch.object(MyClass, 'method')
def test_method(mock_method):
mock_method.return_value = 'mocked'
# Test code here
# Multiple decorators stack bottom-to-top
@patch('module.func2')
@patch('module.func1')
def test_multiple(mock_func1, mock_func2):
# Arguments passed in reverse order of decorators
passfrom mock import patch
# Start patch manually
patcher = patch('module.function')
mock_func = patcher.start()
mock_func.return_value = 'mocked'
try:
# Test code here
pass
finally:
patcher.stop()
# Or use stop_all to stop all active patches
from mock import stop_all
stop_all()from mock import patch
import os
# Patch environment variables
with patch.dict(os.environ, {'KEY': 'value'}):
# os.environ['KEY'] is now 'value'
pass
# Patch module-level dictionary
module_dict = {'key': 'original'}
with patch.dict(module_dict, {'key': 'new', 'extra': 'added'}):
# module_dict now contains updated values
pass
# Clear and replace
with patch.dict(module_dict, {'only': 'this'}, clear=True):
# module_dict only contains {'only': 'this'}
passfrom mock import patch, Mock
# Create patch if target doesn't exist
with patch('nonexistent.module.func', create=True) as mock_func:
mock_func.return_value = 'created'
# Use autospec for automatic specification
with patch('module.Class', autospec=True) as MockClass:
# MockClass has same signature as original Class
instance = MockClass()
# Custom replacement
def custom_replacement(*args, **kwargs):
return 'custom result'
with patch('module.func', new=custom_replacement):
# module.func is replaced with custom_replacement
pass
# Using new_callable
with patch('module.func', new_callable=lambda: Mock(return_value='called')):
# Creates new mock instance each time
passfrom mock import patch
import requests
@patch('requests.get')
def test_api_call(mock_get):
# Mock HTTP response
mock_response = Mock()
mock_response.json.return_value = {'data': 'test'}
mock_response.status_code = 200
mock_get.return_value = mock_response
# Test code that calls requests.get
result = api_function()
assert result == {'data': 'test'}
mock_get.assert_called_once()from mock import patch
class MyClass:
def method(self): pass
obj = MyClass()
# Patch method on specific instance
with patch.object(obj, 'method', return_value='mocked'):
result = obj.method()
assert result == 'mocked'
# Patch method on class (affects all instances)
with patch.object(MyClass, 'method', return_value='mocked'):
result = obj.method()
assert result == 'mocked'Install with Tessl CLI
npx tessl i tessl/pypi-mock