How to Mock Service Call Timeouts in Python
Simulate service calls with configurable timeouts using Mock to patch sleep and randomness, covering success and timeout cases.
Python code
38 linesimport time
from unittest.mock import Mock, patch
# Simulate a service call with configurable timeout
def call_service(service_name, timeout=5):
"""Mock a service call that may time out."""
start = time.time()
print(f"Calling {service_name}...")
# Simulate service latency (randomized for realism)
import random
simulated_latency = random.uniform(0.1, 10)
if simulated_latency > timeout:
print(f"{service_name} timed out after {timeout}s (simulated latency was {simulated_latency:.1f}s)")
raise TimeoutError(f"{service_name} exceeded timeout of {timeout}s")
time.sleep(simulated_latency)
print(f"{service_name} responded in {simulated_latency:.1f}s (within timeout)")
return {"status": "ok", "service": service_name}
if __name__ == "__main__":
# Use mock to prevent actual sleeping during test
with patch("time.sleep", return_value=None), \
patch("random.uniform", return_value=0.5) as mock_random:
# Test successful call within timeout
result = call_service("payment-service", timeout=2)
print(f"Result: {result}")
# Change simulated latency to exceed timeout
mock_random.return_value = 5.0
# Test timeout
try:
call_service("shipping-service", timeout=2)
except TimeoutError as e:
print(f"Caught: {e}")
Output
Calling payment-service...
payment-service responded in 0.5s (within timeout)
Result: {'status': 'ok', 'service': 'payment-service'}
Calling shipping-service...
shipping-service timed out after 2s (simulated latency was 5.0s)
Caught: shipping-service exceeded timeout of 2s
How it works
The call_service function simulates a remote call by generating a random latency with random.uniform and comparing it to a timeout threshold. Patching time.sleep prevents real delays in tests, and patching random.uniform allows deterministic control of latency. The Mock library's return_value attribute lets you change behavior between calls, as shown when setting latency to 5.0 to trigger a timeout. This pattern is useful for unit-testing timeout logic without network or waiting.
Common mistakes
- Forgetting to patch `random.uniform` leads to nondeterministic test outcomes.
- Using `time.sleep` in tests slows execution and can cause flaky CI results.
- Not resetting patch return values between test cases causes unintended behavior.
- Raising `TimeoutError` instead of a custom exception makes error handling brittle.
Variations
- Use `pytest-mock`'s `mocker` fixture to patch time and random functions.
- Create a separate `ServiceClient` class with injectable latency and timeout settings.
Real-world use cases
- Unit-testing service clients with timeouts to ensure proper exception propagation.
- Simulating slow or unresponsive dependencies for resilience testing in microservices.
- Validating retry logic or circuit breaker behavior under controlled latency conditions.
Sponsored
More from Microservices patterns
- BFF aggregation pattern: combine multiple service responses in Python easy
- Backward Compatible Schema Evolution in Python medium
- Bulkhead Thread Pool per Service Mock in Python medium
- CQRS with Separate Read and Write Repositories in Python medium
- Cache-Aside Pattern in Python: Per-Service Mock easy
- Consumer Driven Contract Pact Mock in Python medium
Keep learning
Related tutorials and quizzes for this topic.