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.

Medium Python 3.9+ Aug 9, 2026 Microservices patterns 16 views 0 copies

Python code

38 lines
Python 3.9+
import 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

stdout
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

  1. Use `pytest-mock`'s `mocker` fixture to patch time and random functions.
  2. 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

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Microservices patterns

Related tutorials and quizzes for this topic.