Skip to content

Verifying requests ​

A test checks what the code under test sent: which requests came, how many, by when, and in what order. A server with a journal keeps every request it gets, whatever answered it, and m.VerifyRequests() selects and counts them, on HTTP and gRPC servers alike. A failed check says why: the requests it selected and, when it wanted more, those that came closest, with the parts each one missed.

Do you need it? ​

Most tests don't. To check that a mock was called, use the scope that MustMock returns: it asserts the calls of the mocks it added, with no journal and no criteria to repeat.

go
paid := m.MustMock(mockhttp.Postf("/payments").Reply(mockhttp.Created()))
refund := m.MustMock(mockhttp.Postf("/refunds").Reply(mockhttp.Created()))

// ... the code under test sends its requests ...

paid.AssertCalled(t)           // every mock of the scope was called
paid.AssertNumberOfCalls(t, 1) // and their calls add up to 1
refund.AssertNotCalled(t)      // no mock of the scope was called

Request verification is for what a scope can't see:

  • requests no mock answered;
  • counts across several mocks, or by request parts no single mock matches on;
  • requests the code under test sends in the background, which a check waits for;
  • the order of requests, and a test's own requests on a shared server, with marks;
  • checks from outside Go, over the admin API or MCP.

Checking the journal ​

go
m := mockhttp.MustNew(mockhttp.Setup().Journal("")) // "" keeps the journal in a temporary directory
m.MustStart()
t.Cleanup(m.Close)

// ... the code under test sends its requests ...

m.VerifyRequests().Method("POST").Path(match.Equal("/orders")).Times(t, 1)
m.VerifyRequests().Outcome(journal.OutcomeUnmatched).Never(t)
go
m := mockgrpc.MustNew(mockgrpc.Setup().Journal(""))
m.MustStart()
t.Cleanup(m.Close)

// ... the code under test calls the server ...

m.VerifyRequests().Path(match.Equal("/helloworld.Greeter/SayHello")).
	Body(match.JSONPath("$.name", match.Equal("bob"))).
	Times(t, 1)
sh
curl -X QUERY -H 'Content-Type: application/json' \
  -d '{"method": "POST", "path": "/orders", "count": 1}' \
  http://127.0.0.1:8081/requests/verify
# {"passed": true, "count": 1, "waited_ms": 0}

journal is github.com/caffeine-projects/vlatte/journal, and match is github.com/caffeine-projects/vlatte/match. The checks live in package github.com/caffeine-projects/vlatte/verify, which a server embeds when its setup keeps a journal: a test calls them on the server.

How it works ​

  1. Select. VerifyRequests() selects every request the journal holds. Criteria narrow the selection: the method, path, headers, body, status, outcome, the mock that answered, or the request part of a mock.
  2. Check. Times, AtLeast, AtMost, Never and CountIs assert how many requests the selection holds, and verify.InOrder asserts the order of several selections. A check runs now, or waits for its count without polling.
  3. Report. A failure reports with t.Errorf and returns false. It lists the requests the selection holds, and those that came closest, a line each, without headers or bodies, which may hold secrets.

A check never passes on part of the requests: one whose requests the journal dropped or cleared fails with an error, rather than count what is left.

PageWhat it covers
Selecting requestsThe criteria, request patterns, and how gRPC calls are selected.
Counts and reportsThe assertions, the failure report, and reading the requests.
WaitingChecking a request the code under test sends in the background, or that none comes for a while.
Marks and orderCounting a test's own requests on a shared server, and checking their order.
Admin API and MCPThe same checks for a client in any language, or an AI agent.
TroubleshootingThe errors of a check that can't run, and what to do about each.

The Request journal page covers the journal itself: what each entry holds, where it is kept, and its limits.