How to Mock a Timeout per Dependency Call in Python
This code demonstrates how to simulate and test per-call timeouts for external dependencies using Python's unittest.mock and a simple timing wrapper.
Python code
29 lines```python
import time
from unittest.mock import Mock, patch
def call_dependency(dependency, timeout):
start = time.time()
result = dependency.call()
elapsed = time.time() - start
if elapsed > timeout:
raise TimeoutError(f"Dependency call took {elapsed:.2f}s, exceeding timeout {timeout}s")
return result
if __name__ == "__main__":
# Mock that simulates a slow dependency
slow_dependency = Mock()
slow_dependency.call.side_effect = lambda: time.sleep(0.2) or "data"
# Mock that responds quickly
fast_dependency = Mock()
fast_dependency.call.return_value = "result"
# Test with a short timeout
try:
call_dependency(slow_dependency, timeout=0.1)
except TimeoutError as e:
print(f"Caught: {e}")
# Test with a generous timeout
print(f"Fast dependency result: {call_dependency(fast_dependency, timeout=0.1)}")
Output
Caught: Dependency call took 0.20s, exceeding timeout 0.1s
Fast dependency result: result
How it works
This example uses unittest.mock.Mock to create fake dependencies with controllable behavior via side_effect and return_value. The call_dependency function measures the wall-clock time of the dependency call using time.time() and raises a TimeoutError if the elapsed time exceeds the specified timeout. The slow mock uses a lambda with time.sleep to simulate latency, while the fast mock returns instantly. This pattern lets you test timeout logic without real network or I/O operations.
Common mistakes
- Forgetting that `side_effect` is callable and using it as a value instead of a function
- Measuring time before the call but not accounting for system clock changes or other overhead
- Not mocking `time.time` itself when you need deterministic tests
Variations
- Use `unittest.mock.patch('time.time')` to freeze time for deterministic timeout testing
- Implement a retry wrapper that catches TimeoutError and retries with backoff
Real-world use cases
- Testing circuit breaker logic in microservices when a downstream API call exceeds its budget.
- Verifying that a background job fails fast when an external data source is unresponsive.
- Writing unit tests for a service that enforces a per-request timeout against a legacy database client.
Sponsored
More from System design patterns
- Build a BFF (Backend for Frontend) Mock Aggregator in Python medium
- Builder pattern for mocking complex objects in Python easy
- Circuit Breaker Pattern in Python: Closed, Open, and Half-Open States medium
- Create a Data Helper Class in Python easy
- Domain Driven Design Aggregate Root Example in Python medium
- Facade Pattern in Python with Mock Simplification medium
Keep learning
Related tutorials and quizzes for this topic.