In WireMock, how do withFixedDelay(), withUniformRandomDelay() and withLogNormalRandomDelay() differ?
answer
- three ways to make a stub slow
- one number, two bounds, or a curve
- uniform draws flat between lower and upper
- log-normal takes a median and a sigma
- bigger sigma means a longer slow tail
basics
~20 sWireMock's withFixedDelay holds every matching reply for the same number of milliseconds. WireMock's withUniformRandomDelay samples each pause evenly between a lower and upper bound. WireMock's withLogNormalRandomDelay samples around a median, where a bigger sigma lengthens the slow tail.
solid answer
~40 sAll three are WireMock response-side delays declared on the same `ResponseDefinitionBuilder`, and all three hold the whole reply — status line, headers and body — back before a single byte is written. WireMock's `withFixedDelay(Integer)` takes one millisecond figure and applies it identically on every call, which is what you want when a test asserts a boundary. WireMock's `withUniformRandomDelay(int lower, int upper)` draws a fresh sample from a flat distribution between the two bounds each time the stub answers. WireMock's `withLogNormalRandomDelay(double median, double sigma)` draws from a log-normal curve, where `median` is the 50th percentile in milliseconds and a larger `sigma` lengthens the right-hand tail of slow responses. In MockServer the same idea is reached through `withDelay(`, which takes a `Delay` from factories such as `Delay.milliseconds(`, `Delay.uniform(`, `Delay.logNormal(` and `Delay.gaussian(`.
code
java · 20 linesimport static com.github.tomakehurst.wiremock.client.WireMock.*;
stubFor(get(urlPathEqualTo("/fitting/patients/AB-4471/audiogram"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("{\"patientId\":\"AB-4471\",\"earSide\":\"left\"}")
.withFixedDelay(3000)));
stubFor(get(urlPathEqualTo("/fitting/devices/HX-9002/telemetry"))
.willReturn(aResponse()
.withStatus(200)
.withBodyFile("telemetry.json")
.withUniformRandomDelay(200, 1200)));
stubFor(post(urlPathEqualTo("/fitting/sessions"))
.willReturn(aResponse()
.withStatus(202)
.withBody("{\"fittingStatus\":\"PENDING\"}")
.withLogNormalRandomDelay(400, 1)));go deeper
Know that a WireMock stub can be made slow on purpose, and that the delay is attached to the response builder inside willReturn, not to the request matcher. Be able to name WireMock's withFixedDelay.
Be ready to explain all three WireMock methods and their parameters: one figure for fixed, a lower and an upper bound for uniform, a median and a sigma for log-normal. Say what a single sample looks like in each case.
Show that you know a WireMock delay is spent as a sleep on the request thread unless the server runs with --async-response-enabled, and that only bounds, never exact times, are safely assertable against a random delay.
Own the question of which shape a suite standardises on. Argue when a long-tailed WireMock log-normal delay earns its flakiness budget, and when a fixed delay or a truncated ceiling is the more honest instrument.
A stub server answers from a canned definition, so it replies as fast as the process can write bytes — often in single-digit milliseconds. That is faster than any real dependency will ever be, and it quietly hides every branch a client has for waiting: progress indicators, cancellation, deadlines, back-pressure. WireMock's delay methods exist to put the slowness back on purpose, and there are three sampling shapes to choose between. ## Where a WireMock delay is declared Every delay discussed here belongs to WireMock's `ResponseDefinitionBuilder` — the object `aResponse()` returns and `willReturn(` consumes. It is a property of the **reply**, not of the matcher: a WireMock delay changes *when* a stub answers, never *which* stub is selected. Because it is part of the response definition it serialises into the stub mapping alongside the status and body, so a delay written with WireMock's `withFixedDelay(` appears in the committed mapping file as `fixedDelayMilliseconds`, and the two random forms appear as a `delayDistribution` object. ## The three methods, side by side | Product | Method | Parameters | What one call gets | |---|---|---|---| | WireMock | `withFixedDelay(Integer)` | one figure, milliseconds | the same pause every time | | WireMock | `withUniformRandomDelay(int, int)` | lower and upper bound | an even draw between the bounds | | WireMock | `withLogNormalRandomDelay(double, double)` | median and sigma | a skewed draw with a long tail | - WireMock's `withFixedDelay(3000)` is the deterministic instrument: every request that stub answers waits the same three seconds, which is exactly what a test asserting a boundary needs. - WireMock's `withUniformRandomDelay(200, 1200)` samples afresh on every call from a flat distribution, so any value between the bounds is equally likely and nothing outside them ever happens. - WireMock's `withLogNormalRandomDelay(400, 1)` samples from a log-normal curve whose `median` argument is the 50th percentile in milliseconds, while `sigma` is the standard deviation of the underlying normal distribution. - A larger `sigma` in WireMock's `withLogNormalRandomDelay(` produces a longer right-hand tail — most calls land near the median and a few land far above it, which is the shape real service latency actually has. - WireMock's three-argument `withLogNormalRandomDelay(double median, double sigma, Double maxValue)` truncates that tail by resampling anything above `maxValue`, so a long-tailed stub cannot occasionally stall a whole suite. WireMock rejects a `maxValue` below the median outright. - Both random forms are convenience wrappers: WireMock's `withRandomDelay(DelayDistribution)` is the underlying method, and the uniform and log-normal helpers simply construct the distribution for you. ## What all three have in common WireMock applies a response delay *before* it writes anything at all. Under WireMock's `withFixedDelay(3000)` the client does not receive an early status line and then stall; it sees nothing whatsoever on the socket for three seconds, and then the entire reply — status, headers and body — arrives together. That is deliberately different from WireMock's `withChunkedDribbleDelay(`, which is slow *while transferring* rather than slow *before answering*, and it is why that method is a separate property rather than a fourth distribution. The wait itself is not free. By default WireMock spends it as a sleep on the thread handling the request, so a stub server holding many delayed responses at once can exhaust its container threads long before the delay figures themselves look large. Starting WireMock with `--async-response-enabled` (or building the server with `wireMockConfig().asynchronousResponseEnabled(true)`) moves the waiting onto a scheduled executor instead, which is what makes generous delays affordable under concurrency. ## Choosing one for a hearing-aid fitting stub set 1. Reach for WireMock's `withFixedDelay(` when the test asserts something about a specific duration — that the fitting screen still shows its progress indicator, or that the client gives up precisely where you expect it to. 2. Reach for WireMock's `withUniformRandomDelay(` when you want ordinary jitter with a hard ceiling, for instance a `GET /fitting/devices/{deviceSerial}/telemetry` stub that should never answer instantly but should never be pathological either. 3. Reach for WireMock's `withLogNormalRandomDelay(` when the point is that most calls are quick and a few are not — the shape that finds the code path nobody exercised — usually with the third `maxValue` argument set so the tail stays bounded. ## Mistakes worth naming - Treating WireMock's `withUniformRandomDelay(` and `withLogNormalRandomDelay(` as interchangeable. Uniform has hard bounds and no tail; log-normal has a median and an unbounded tail unless you truncate it. - Reading `sigma` in WireMock's `withLogNormalRandomDelay(` as a maximum. It is a spread parameter; the maximum is the optional third argument. - Asserting an exact elapsed time against a WireMock stub that uses a random delay. The sample changes on every call, so only bounds are safely assertable. - Assuming a WireMock delay slows the *request*. It does not: the request is fully received and matched first, and only the reply is held back. - Forgetting that a WireMock delay is serialised into the mapping, which means it travels with the file to every other instance that loads it.
- What does the optional third argument to WireMock's withLogNormalRandomDelay do?It is `maxValue`, a ceiling in milliseconds. WireMock resamples any draw above it, which truncates the long right-hand tail of the log-normal distribution. Without it a stub can occasionally produce a delay far larger than the median and stall a suite; with it the shape stays skewed but bounded. WireMock rejects a `maxValue` lower than the median.
- How would you assert against a WireMock stub that uses withUniformRandomDelay?On bounds, never on an exact figure. The sample changes on every call, so assert that the observed duration falls between the lower and upper arguments, or assert the client behaviour the delay is meant to provoke — a progress indicator that stayed on screen, a deadline that fired. An exact-time assertion against a random WireMock delay is a flake waiting to happen.
saying these in an interview costs you the question
- Says WireMock's uniform and log-normal delays are interchangeable
- Reads sigma in WireMock's log-normal delay as a maximum
- Thinks a WireMock delay slows the request, not just the reply
- Asserts an exact elapsed time against a random WireMock delay
- Believes a WireMock delay changes which stub matches