Python's unittest.mock module lets you replace parts of your system during tests. Essential for isolating code and testing without real dependencies.
Basic Mock
from unittest.mock import Mock
# Create a mock
mock_db = Mock()
# Configure return values
mock_db.get_user.return_value = {'id': 1, 'name': 'Alice'}
# Use it
result = mock_db.get_user(1)
print(result) # {'id': 1, 'name': 'Alice'}
# Verify calls
mock_db.get_user.assert_called_once_with(1)MagicMock
Includes default implementations of magic methods:
from unittest.mock import MagicMock
mock = MagicMock()
# Magic methods work automatically
len(mock) # Returns MagicMock
iter(mock) # Returns iterator
mock[0] # Returns MagicMock
mock['key'] # Returns MagicMock
# Configure magic methods
mock.__len__.return_value = 5
print(len(mock)) # 5patch Decorator
Replace objects during tests:
from unittest.mock import patch
# In myapp.py
import requests
def fetch_data(url):
return requests.get(url).json()
# In test_myapp.py
from unittest.mock import patch
@patch('myapp.requests.get')
def test_fetch_data(mock_get):
mock_get.return_value.json.return_value = {'data': 'test'}
result = fetch_data('http://api.example.com')
assert result == {'data': 'test'}
mock_get.assert_called_once_with('http://api.example.com')patch Context Manager
from unittest.mock import patch
def test_something():
with patch('myapp.external_service') as mock_service:
mock_service.call.return_value = 'mocked'
result = my_function()
assert result == 'mocked'patch.object
Patch an attribute on an object:
from unittest.mock import patch
class MyClass:
def method(self):
return 'real'
obj = MyClass()
with patch.object(obj, 'method', return_value='mocked'):
print(obj.method()) # 'mocked'
print(obj.method()) # 'real'Patching Multiple Objects
from unittest.mock import patch
@patch('myapp.service_a')
@patch('myapp.service_b')
def test_function(mock_b, mock_a): # Note: reverse order!
mock_a.call.return_value = 'a'
mock_b.call.return_value = 'b'
result = my_function()
# Or with context managers
def test_function():
with patch('myapp.service_a') as mock_a, \
patch('myapp.service_b') as mock_b:
# test code
passConfiguring Return Values
from unittest.mock import Mock
mock = Mock()
# Simple return
mock.method.return_value = 42
# Different returns each call
mock.method.side_effect = [1, 2, 3]
print(mock.method()) # 1
print(mock.method()) # 2
print(mock.method()) # 3
# Raise exception
mock.method.side_effect = ValueError("error")
# Callable side effect
def custom_logic(x):
return x * 2
mock.method.side_effect = custom_logic
print(mock.method(5)) # 10Assertions
from unittest.mock import Mock, call
mock = Mock()
# Call verification
mock.method(1, 2, key='value')
mock.method.assert_called()
mock.method.assert_called_once()
mock.method.assert_called_with(1, 2, key='value')
mock.method.assert_called_once_with(1, 2, key='value')
# Multiple calls
mock.method(1)
mock.method(2)
mock.method(3)
mock.method.assert_any_call(2) # Was it ever called with 2?
assert mock.method.call_count == 3
# Verify call order
mock.method.assert_has_calls([
call(1),
call(2),
call(3)
])spec and autospec
Prevent typos and ensure mock matches real API:
from unittest.mock import Mock, create_autospec
class RealClass:
def method(self, x, y):
return x + y
# Basic spec
mock = Mock(spec=RealClass)
mock.method(1, 2) # OK
mock.nonexistent() # AttributeError!
# Autospec - also checks signatures
mock = create_autospec(RealClass)
mock.method(1, 2) # OK
mock.method(1) # TypeError - missing argument!Patching Properties
from unittest.mock import patch, PropertyMock
class MyClass:
@property
def value(self):
return expensive_computation()
with patch.object(MyClass, 'value', new_callable=PropertyMock) as mock_value:
mock_value.return_value = 42
obj = MyClass()
print(obj.value) # 42Async Mocks
from unittest.mock import AsyncMock, patch
import asyncio
async def fetch_data():
return await external_api()
@patch('myapp.external_api', new_callable=AsyncMock)
async def test_fetch(mock_api):
mock_api.return_value = {'data': 'test'}
result = await fetch_data()
assert result == {'data': 'test'}
# Run with
asyncio.run(test_fetch())Mocking Datetime
from unittest.mock import patch
from datetime import datetime
def get_greeting():
hour = datetime.now().hour
if hour < 12:
return "Good morning"
return "Good afternoon"
@patch('myapp.datetime')
def test_morning(mock_datetime):
mock_datetime.now.return_value.hour = 9
assert get_greeting() == "Good morning"
@patch('myapp.datetime')
def test_afternoon(mock_datetime):
mock_datetime.now.return_value.hour = 15
assert get_greeting() == "Good afternoon"Mocking File Operations
from unittest.mock import patch, mock_open
def read_config(path):
with open(path) as f:
return f.read()
def test_read_config():
mock_data = "key=value"
with patch('builtins.open', mock_open(read_data=mock_data)):
result = read_config('config.txt')
assert result == "key=value"Mocking Environment Variables
from unittest.mock import patch
import os
@patch.dict(os.environ, {'API_KEY': 'test-key'})
def test_with_env():
assert os.environ['API_KEY'] == 'test-key'Reset Mocks
from unittest.mock import Mock
mock = Mock()
mock.method(1)
mock.method(2)
# Reset all call info
mock.reset_mock()
assert mock.method.call_count == 0
mock.method.assert_not_called()Common Patterns
Database Mock
from unittest.mock import Mock
def get_user_orders(db, user_id):
user = db.get_user(user_id)
return db.get_orders(user['id'])
def test_get_user_orders():
mock_db = Mock()
mock_db.get_user.return_value = {'id': 1, 'name': 'Alice'}
mock_db.get_orders.return_value = [{'id': 100}, {'id': 101}]
orders = get_user_orders(mock_db, 1)
assert len(orders) == 2
mock_db.get_user.assert_called_once_with(1)HTTP Client Mock
from unittest.mock import patch, Mock
@patch('requests.get')
def test_api_call(mock_get):
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {'success': True}
mock_get.return_value = mock_response
result = call_api('/endpoint')
assert result['success'] is TrueSummary
Key mocking patterns:
- Mock/MagicMock: Create mock objects
- patch: Replace during tests (decorator or context manager)
- return_value: Configure what mock returns
- side_effect: Multiple returns, exceptions, or custom logic
- spec/autospec: Ensure mock matches real API
- assert_called_*: Verify interactions
Mocking isolates your code from dependencies, making tests fast and reliable.
React to this post: