Mock Return Values & Side Effects
Control what mocks return and how they behave using return_value,
side_effect, and related attributes. This lets you simulate various
scenarios in your tests.
return_value
from unittest.mock import Mock
mock_db = Mock()
mock_db.fetch_user.return_value = {"id": 1, "name": "Alice"}
result = mock_db.fetch_user(1)
print(result) # {"id": 1, "name": "Alice"}
# For chained calls
mock_db.fetch_user.return_value.name = "Bob"
print(mock_db.fetch_user(1).name) # "Bob"
side_effect for Exceptions
from unittest.mock import Mock, side_effect
# Simulate an exception
mock_api = Mock()
mock_api.get.side_effect = ConnectionError("Network timeout")
with self.assertRaises(ConnectionError):
mock_api.get("/users")
# Verify the exception message
with self.assertRaises(ConnectionError) as ctx:
mock_api.get("/users")
self.assertEqual(str(ctx.exception), "Network timeout")
side_effect for Multiple Values
mock_api = Mock()
mock_api.get.side_effect = [
{"status": 200, "data": "first"},
{"status": 200, "data": "second"},
ConnectionError("timeout"),
]
print(mock_api.get()) # {"status": 200, "data": "first"}
print(mock_api.get()) # {"status": 200, "data": "second"}
# mock_api.get() raises ConnectionError
# Use a function for dynamic responses
def dynamic_response(url):
if "users" in url:
return {"users": []}
return {"error": "not found"}
mock_api.get.side_effect = dynamic_response
call_count and call_args
mock_service = Mock()
mock_service.process()
self.assertEqual(mock_service.process.call_count, 1)
mock_service.process.assert_called_once()
mock_service.process("arg1", key="value")
mock_service.process.assert_called_with("arg1", key="value")
# Access call arguments
print(mock_service.process.call_args)
# call('arg1', key='value')
Key Takeaway
Use return_value for static responses, side_effect for exceptions
or dynamic behavior, and call_args/call_count to verify how
mocks were called.