Latency Simulation: Test What Breaks When APIs Slow Down
Latency Simulation — Latency simulation makes a mock respond after a configurable delay, so you can test how clients behave when the real API is slow — not just when it is instant.
Definition
Most outages are slowness, not errors. A mock that adds a fixed or jittered delay exposes clients that assume instant responses and silently time out in production.
The mechanism is simple: per response, you set a fixed delay (say 1200ms) or a random jitter window, and the mock holds the connection open before replying. Combined with fault injection — resets, empty bodies, 500s — it reproduces the messy conditions real networks produce but tests rarely cover.
Why it matters: clients that look fine against an instant mock frequently fall apart under load. A spinner that never clears, a retry storm that hammers a struggling service, a timeout set too low — all of these only show up when the mock is allowed to be slow. Latency simulation turns that blind spot into a routine assertion.
Use it deliberately, not constantly. A delay on every call slows the whole suite, so most teams reserve latency and fault scenarios for a focused set of tests rather than the happy-path run. The goal is to prove the failure paths handle pressure, then get out of the way for the fast tests.
How it works
Latency simulation makes a mock hold the connection open before replying, for a fixed delay or a random jitter window. Combined with fault injection — resets, empty bodies, 500s — it reproduces the messy conditions real networks produce but tests rarely cover.
The mechanism is per-response: you set a delay like 1200ms or a jitter range, and the mock waits before sending the body. Clients that assume instant responses then expose their real behavior under pressure.
A minimal example
In WireMock a mapping uses `withFixedDelay(1200)` to force a slow 401, or a jitter range for variable slowness. Prism and MockServer offer equivalent per-response delay settings. The effect is identical across tools: the same request now takes noticeably longer, surfacing timeout and spinner bugs.
Pair the delay with a fault handler to simulate a dropped connection, and a 500 variant to cover server errors. A small set of these stubs — slow, broken, errored — is the cheapest hardening you can add.
When you need it
Use latency simulation because most outages are slowness, not errors. A client that looks fine against an instant mock frequently falls apart under load: a spinner that never clears, a retry storm that hammers a struggling service, a timeout set too low. Delays turn that blind spot into a routine assertion.
It’s essential for any client that wraps a network call in a UI, a mobile app, or a retry policy. Proving the failure paths handle pressure is worth more than another happy-path test.
When you don’t
Don’t apply it to every call — a delay on each response slows the whole suite and lengthens CI for no extra signal. Reserve latency and faults for a focused set of tests, then keep the happy-path run fast.
Don’t use it to simulate business logic. Latency proves clients tolerate slowness; it says nothing about whether the response is correct. Keep correctness in the stub’s body and slowness in the delay, as two separate concerns.