skip to content

Asserting What Arrived

Using the server as a witness: asserting that a matching request arrived, pinning how many times, and pulling the recorded requests back to assert on their bodies and headers.

on this pageshow

explore

questions

5

In MockServer, how do you verify that a POST to /catalogue/v1/holds actually arrived?

level: juniorimportance: must knowfreq 68%

answer

  1. the server is the only witness
  2. every received request is journalled
  3. a pattern, not a full description
  4. MockServerClient.verify plus a request definition
  5. VerificationTimes.once pins it to one

basics

~20 s

MockServer keeps a journal of every request it receives, and MockServerClient.verify asserts against it. Pass a request definition describing the POST plus a VerificationTimes count. When nothing matches, verify throws an AssertionError listing the requests the journal did record.

solid answer

~40 s

MockServer's request journal records every request the server received, and `MockServerClient.verify` is how a test interrogates it. Build a request definition with the static `request()` factory — `request().withMethod("POST").withPath("/catalogue/v1/holds")` — and hand it to `verify`, optionally with a `VerificationTimes` count such as `VerificationTimes.once()`. Omit the count and the assertion means only "at least one matching request arrived". MockServer matches that definition against the journal with the same rules it uses to pick an expectation, so a definition naming only a method and path is satisfied by any body and any headers. If nothing matches, `verify` throws an `AssertionError` whose message carries the requests the journal actually held, which usually shows the client hit `/catalogue/v1/hold` or sent a `GET`. WireMock's count matchers are `exactly(`, `lessThan(`, `lessThanOrExactly(`, `moreThan(` and `moreThanOrExactly(`, and it has no `never()`.

code

java · 10 lines
java
import static org.mockserver.model.HttpRequest.request;
import org.mockserver.verify.VerificationTimes;

// the service under test has just placed a hold on a catalogue title
mockServerClient.verify(
    request()
        .withMethod("POST")
        .withPath("/catalogue/v1/holds"),
    VerificationTimes.once()
);

go deeper

for a junior

Be ready to write the call from memory: MockServerClient.verify with a request definition built by request(), with the method and path set. Say plainly that failure throws rather than returning false.

for a middle

Explain that the definition is a pattern matched against the journal, so unnamed headers and bodies are unconstrained, and that omitting VerificationTimes means at least once rather than exactly once.

for a senior

Show where the verification sits in a test that also asserts on your own code's outcome, and how you read the AssertionError message to separate a client bug from a badly written request definition.

for a principal

Set the standard for how much of a request a verification may pin — path and method only, or body too — and decide who maintains those definitions when the catalogue contract shifts.

## Why the server has to be the witness A test that puts a stub server in front of a dependency can prove two different things. The first is that the code under test coped with the canned reply — the branch it took, the value it returned, the error it surfaced. Assertions on your own code cover that. The second is that the code **sent the right request at all**: that "place a hold on this title" really produced a `POST /catalogue/v1/holds`, rather than short-circuiting on a cached value or swallowing an exception in a `catch` block nobody noticed. No assertion inside your own process can see that, because the only component that saw the bytes on the wire is the stub server. MockServer answers it from its **request journal** — the record it keeps of every request the server received while the test ran, held independently of which expectation, if any, produced the reply. Verifying is nothing more than asking that journal a question and failing the test when the answer is wrong. ## The anatomy of a MockServer verification `MockServerClient.verify` takes a request definition and, optionally, a count. - `request()` is the static factory on MockServer's `HttpRequest` that starts the definition. - `withMethod("POST")` and `withPath("/catalogue/v1/holds")` narrow it to the call you care about. - A `VerificationTimes` argument pins how many matching requests the journal must hold. MockServer's set is `never()`, `once()`, `exactly(int)`, `atLeast(int)`, `atMost(int)` and `between(int, int)`. - Omit the count and the assertion means only "at least one matching request arrived". - On success the call returns normally; on failure it throws an `AssertionError`. ```java mockServerClient.verify( request().withMethod("POST").withPath("/catalogue/v1/holds"), VerificationTimes.once()); ``` ## What the definition asserts, and what it silently ignores The definition is a **pattern**, not a description of the whole request. MockServer matches it against the journal with the same rules it uses to select an expectation, so every aspect the pattern does not mention is left unconstrained. That is the single most common reason a verification passes while the integration is broken. | verification call | passes when the journal holds | says nothing about | |---|---|---| | `verify(request().withPath("/catalogue/v1/holds"))` | one or more requests on that path | the method, the body, the headers | | `verify(request().withMethod("POST").withPath("/catalogue/v1/holds"), VerificationTimes.once())` | exactly one POST on that path | the body and the headers | | `verify(request().withPath("/catalogue/v1/holds"), VerificationTimes.never())` | no request at all on that path | every other path | ## Reading the failure When the assertion fails, MockServer's `AssertionError` carries both the definition you asked for and the requests the journal actually held. In practice that message does most of the diagnosis: 1. The recorded entry shows `/catalogue/v1/hold` where you asked for `/catalogue/v1/holds` — a typo or an unencoded segment in the client. 2. The recorded entry is a `GET` where you asked for a `POST` — the code fell into a read path and never attempted the write. 3. The journal holds two matching requests where you asked for `once()` — a retry, or a duplicated call the feature never intended. 4. The journal is empty — the client never reached this server, which usually means it was pointed at the wrong port or base URL. ## Where the assertion belongs in the test A verification is a second assertion, not a replacement for the first. The usual shape of a catalogue test is: - Arrange an expectation so `POST /catalogue/v1/holds` answers with `201` and a body carrying `holdId` and `queuePosition`. - Act by calling your own service method. - Assert on what your code returned or stored — the hold id it surfaced to its caller. - Verify against the journal that the outbound request was actually made, once. Drop the last step and a client that never called the catalogue can still pass. Drop the third and you have proved traffic went out and nothing at all about whether the feature worked. ## Common mistakes - Treating a green `verify` as proof the body was right. It proves only that a request matching the pattern you wrote arrived; a pattern naming just a path is satisfied by an empty POST. - Assuming a count is implied. Without a `VerificationTimes` argument the assertion is "at least once", so a client that fires the hold three times still passes. - Confusing the two sides of the API. `withStatusCode` belongs to MockServer's `response()` on the expectation; verification is about the request and takes no status at all. - Verifying before the work has finished. If the catalogue call runs on another thread, the journal may not hold the request yet when the assertion executes. - Reading a passing verification as proof that an expectation matched. The journal records what arrived, not what answered it.

  • What does a MockServer verification with no VerificationTimes argument assert?
    It asserts that at least one request matching the definition reached the server. The journal may hold five identical hold requests and the assertion still passes. Pass `VerificationTimes.once()` — or `exactly(1)` — when the count is part of what you are proving, which for a non-idempotent call such as placing a hold it usually is.
  • Your verify fails but the client definitely called the catalogue. Where do you look first?
    The `AssertionError` message lists the requests the journal did hold, so compare them field by field against the definition you wrote. Most failures are a path that differs by a segment or a trailing slash, a method mismatch, or an assertion that ran before an asynchronous call had completed.
  • Does a passing MockServer verification prove that an expectation matched the request?
    No. The journal records requests the server received, not which expectation answered them, so a request that matched nothing at all still satisfies `verify`. Pair the verification with an assertion on what your own code did with the reply, or the test can be green while the client never received the response you staged.

saying these in an interview costs you the question

  • Thinks a passing verify proves the request body was correct
  • Believes verify with no count argument asserts exactly one request
  • Expects verify to return a boolean instead of throwing on failure
  • Confuses the response builder's withStatusCode with a verification argument
  • Assumes the journal only records requests that an expectation matched
open as a page

In MockServer, what does each VerificationTimes factory assert about how often a request arrived?

level: middleimportance: must knowfreq 62%

basics

~20 s

VerificationTimes carries six factories: never, once, exactly, atLeast, atMost and between. Each turns a MockServer verification from at least one matching request into a precise count assertion, so a duplicated or missing hold request fails the test rather than passing.

open as a page

In MockServer, how does VerificationTimes.never differ from verifyZeroInteractions on a catalogue test?

level: seniorimportance: must knowfreq 52%

basics

~20 s

MockServer's VerificationTimes.never asserts that no request matching one definition arrived, so it says nothing about other traffic. verifyZeroInteractions asserts the journal is empty outright. A never assertion built on a mistyped path passes vacuously; the empty-journal check cannot.

open as a page

When should a MockServer suite assert with verify counts rather than retrieved request bodies?

level: seniorimportance: should knowfreq 46%

basics

~20 s

Use MockServer verify counts for facts about traffic: the hold call happened once, the cancellation never did. Reach for retrieveRecordedRequests only where a field carries contract meaning, because every field you assert is one the catalogue can later change.

open as a page

In MockServer, why retrieve recorded catalogue hold requests instead of asserting the whole body in verify?

level: seniorimportance: should knowfreq 50%

basics

~20 s

MockServer's verify answers only match or no match, so a whole-body pattern breaks on any generated field. retrieveRecordedRequests hands the received requests back as objects, so your own assertions can target the fields that matter and report which one differed.

open as a page