skip to content

A WireMock stub for a vineyard harvest-log endpoint never matches — how do you diagnose it?

level: seniorimportance: should knowfreq 55%

answer

  1. nothing matched, so ask what nearly did
  2. the server kept the request anyway
  3. unmatched list first, near-miss report second
  4. each near miss scores a distance
  5. WireMock findNearMissesForAllUnmatched, closest first

basics

~20 s

WireMock records every request that no stub mapping served. Its near-miss report ranks the closest mapping for each of those, scoring how far apart they are. Read the field the report names as differing, then fix the stub or the client.

solid answer

~40 s

Start from the two things WireMock already keeps for you. WireMock's `GET /__admin/requests/unmatched` lists every request that no stub mapping served — in a vineyard harvest-log suite that is typically the `POST /vineyard/harvest-logs` call your test made. Then ask for the near-miss report, either as `GET /__admin/requests/unmatched/near-misses` or as `WireMock.findNearMissesForAllUnmatched()` from Java. Each WireMock `NearMiss` it returns carries the `LoggedRequest`, the stub mapping it was compared against, and a `MatchResult` whose `getDistance()` scores the gap, so the list arrives closest-first and you can read off which field actually differed — the mapping wanted header `X-Vineyard-Estate: ridgecrest`, the client sent `ridge-crest`. In MockServer, enabling `detailedMatchFailures` makes its log record which matcher rejected the request, which is how that server reaches the same information without a ranked report. Then fix whichever side is wrong and re-run.

code

java · 13 lines
java
import static com.github.tomakehurst.wiremock.client.WireMock.*;

stubFor(post(urlPathEqualTo("/vineyard/harvest-logs"))
    .withHeader("X-Vineyard-Estate", equalTo("ridgecrest"))
    .withRequestBody(matchingJsonPath("$.blockId"))
    .willReturn(aResponse().withStatus(201)));

// the client posts, nothing matches, the test sees 404
for (var miss : findNearMissesForAllUnmatched()) {
    System.out.println(miss.getRequest().getUrl());
    System.out.println(miss.getMatchResult().getDistance());
    System.out.println(miss);
}

go deeper

for a junior

Know that WireMock keeps the requests nothing served, and that a 404 from a stub server is a starting point rather than a verdict. Be able to name the unmatched-requests endpoint when asked where to look first.

for a middle

Be ready to explain the difference between the unmatched list and the near-miss report, and what a WireMock NearMiss holds: the logged request, the mapping it was compared against, and a MatchResult whose distance scores the gap.

for a senior

Show the diagnosis loop, not just the endpoint. Talk about deciding from the diff whether the stub or the client is wrong, and about the case where the request is missing from the journal entirely because it never reached this server.

for a principal

Own the question of how a large suite surfaces this automatically, so a failing run prints the near-miss report instead of leaving every engineer to reproduce the mismatch by hand, and be clear about what that costs in log volume.

## Why an unmatched request is not a dead end When a request arrives that no stub mapping serves, WireMock answers it with a 404 — and that response is the *least* informative thing it produces. The request itself goes into the request journal exactly like a served one, as a `LoggedRequest` carrying the method, the absolute URL, the headers, the cookies and the body as WireMock parsed them. Because that record survives the failure, WireMock can afterwards answer a much better question than "did it match?": it can tell you **which stub mapping came closest, and on which field the two disagreed**. That is the near-miss machinery, and on a vineyard harvest-log suite it turns a long stare at a 404 into a short read. ## The four things you can ask WireMock for | ask WireMock for | what comes back | |---|---| | `GET /__admin/requests/unmatched` | the requests that no stub mapping served | | `GET /__admin/requests/unmatched/near-misses` | those requests, each with the mappings nearest to it, scored | | `POST /__admin/near-misses/request` | the mappings nearest to a request you supply in the body | | `POST /__admin/near-misses/request-pattern` | the logged requests nearest to a request pattern you supply | From Java the same lists have entry points, and the first pair is a genuine trap: - The **static** call is `WireMock.findUnmatchedRequests()`. It delegates to the **instance** method `findAllUnmatchedRequests()` on a configured `WireMock` client. The two names are not interchangeable. - The near-miss equivalent is `WireMock.findNearMissesForAllUnmatched()`. - WireMock's `findNearMissesFor(...)` is the targeted form, for when you already hold the one request or pattern you care about. The first list tells you *that* nothing matched. Only the second tells you *why*. ## What a WireMock NearMiss carries A WireMock `NearMiss` is a small triple, and understanding it is most of the skill: 1. the request — a `LoggedRequest`, exactly as WireMock received and parsed it; 2. the candidate it was compared against — a stub mapping, or a request pattern in the pattern-first direction; 3. the WireMock `MatchResult` of that comparison, whose `getDistance()` is a normalised score where **0 means every matcher passed** and **1 means nothing lined up at all**. Because the score is a single number, the report can be ordered, and it is: closest first. In practice the top entry is the mapping you meant to hit, and the difference between its expectations and the logged request is the bug. ## Working a vineyard harvest-log failure end to end Say a test registers a mapping for `POST /vineyard/harvest-logs` requiring the header `X-Vineyard-Estate: ridgecrest` and a JSON body containing `blockId`, and the client under test gets a 404 instead of the 201 it expected. The loop is short and it is always the same: 1. Fetch the unmatched list. Confirm the request is actually there — if it is not, the client never reached this server, and the port rather than the matcher is the problem. 2. Fetch the near-miss report. Read the top entry: its distance, and which line of the comparison failed. 3. Decide which side is wrong. If the mapping wanted `ridgecrest` and the request carried `ridge-crest`, the client is building a bad header. If the mapping demanded a `blockId` the real API never sends, the mapping is over-specified and the fix belongs in the test. 4. Change one thing and re-run. After the fix, that request should not appear in the unmatched list at all. ## Reading the report without over-reading it - Distance ranks *closeness to matching*. It never tells you which mapping would win if two of them both matched — that is a different mechanism and a different question. - A distance of 0 cannot appear for a request sitting in the unmatched list, because 0 means every matcher passed, which is a match. - An empty near-miss report means there were no mappings on that server to score against, which usually points at registration order or at the wrong instance. - The report compares parsed structures, so a fault in framing or encoding can make an otherwise sensible diff look absurd. - The report is per request. A distance is only meaningful next to the other candidates for that same request, never across requests. ## The habit worth keeping Never diagnose a stub-server failure from the status code alone. WireMock has already written down what arrived and what nearly served it, and the whole skill is knowing that both records exist, asking for them in that order, and letting the diff rather than a guess decide whether the stub or the client is at fault. Teams that wire the near-miss report into their failure output stop reproducing mismatches by hand entirely: the evidence is in the report the first time the test goes red, which is the only time anyone will read it.

  • Your WireMock near-miss report comes back empty even though the test got a 404 — what does that tell you?
    That the server had no stub mappings to compare against at all. Near misses are scored against the mappings actually registered, so an empty report points at registration or at the wrong instance rather than at a bad matcher. Check the port the client used, and check that your WireMock `stubFor(...)` calls ran before the request rather than after it.
  • How do you get a near-miss report for a request that is not in the journal at all?
    Post the request you are unsure about to WireMock's `POST /__admin/near-misses/request` and it reports the stub mappings nearest to it, without that request ever having been served. WireMock's `POST /__admin/near-misses/request-pattern` does the mirror image: give it a request pattern and it names the logged requests closest to that pattern, which is the direction you want when you suspect the mapping.

saying these in an interview costs you the question

  • Says an unmatched request leaves no trace, so nothing can be inspected
  • Confuses WireMock's requests/unmatched with mappings/unmatched, which lists stubs never served
  • Reads the 404 body only and never asks for the near-miss report
  • Assumes the largest distance marks the closest mapping, when zero means an exact match
  • Thinks a near miss predicts which stub will serve the request next time