Richard Hatherall By Richard Hatherall 3 min read webmocks tutorial delphi

Asserting HTTP requests with WebMocks in Delphi

The other half of testing HTTP code with WebMocks: verifying that the right requests were made, with the right details, the right number of times.

Asserting HTTP requests with WebMocks in Delphi
Contents
  1. A basic assertion
  2. Asserting on request details
  3. Matching variable URIs
  4. Where assertions sit in the test
  5. What next?

The previous three articles in this series covered the mocking side of testing HTTP clients with WebMocks: stubbing requests, defining the responses to return, and matching the incoming traffic that came through. That's half the job. The other half is the question every test eventually asks: did my code make the request it was supposed to?

That's where assertions come in. Where StubRequest says "when this request comes in, respond with X," Assert says "after the test runs, verify that this request was made (or wasn't)."

A basic assertion

The simplest assertion checks that a request was made:

procedure TMyTests.CreateUser_SendsPostRequest;
begin
  WebMock.StubRequest('POST', '/users').ToRespond.WithStatus(201);

  Client.CreateUser('alice@example.com');

  WebMock.Assert.Post('/users').WasRequested;
end;

WebMocks provides shorthand methods for each common HTTP verb: Get, Post, Put, Patch, Delete, and Head. They all take a path string and read like English at the call site. The assertion fails if the test didn't make a matching request.

WasNotRequested is just as useful, particularly when business logic decides whether to make the call at all. Cache hits, change detection, feature flags, rate-limit checks: anywhere the network request is conditional, you want a test that exercises the no-request path.

procedure TMyTests.GetUser_WhenCached_DoesNotFetchFromServer;
begin
  WebMock.StubRequest('GET', '/users/1').ToRespond.WithStatus(200);
  Client.PrimeCache(1, existingUser);

  Client.GetUser(1);

  WebMock.Assert.Get('/users/1').WasNotRequested;
end;

If the cache check regresses and the client fetches anyway, the test catches it.

Asserting on request details

Often "the right method and path were used" isn't enough; you want to confirm the request also carried the expected headers, query parameters, or body. The full matcher vocabulary from the previous article on request matching is available on assertions:

WebMock.Assert
  .Post('/users')
  .WithHeader('content-type', 'application/json')
  .WithJSON('email', 'alice@example.com')
  .WasRequested;

WithHeader, WithJSON, WithFormData, WithQueryParam, WithBody, WithXML, and the bulk WithHeaders: the same set that drives StubRequest, with the regex variants and typed JSON matching (string, integer, float, boolean) all working the same way. If you can match a request to stub it, you can match it to assert it was made.

Matching variable URIs

Tests often deal with URIs that vary at runtime: a dynamic resource ID, a generated session token, a request-specific path. For those, fall back to the long-hand Request form, which accepts either a string or a regular expression for the URI:

uses
  System.RegularExpressions;

WebMock.Assert
  .Request('GET', TRegEx.Create('/users/\d+'))
  .WasRequested;

The verb shorthands (Get, Post, etc.) only take string URIs; the long-hand Request(method, regex) is the form to reach for when the URI isn't fixed.

Where assertions sit in the test

A WebMocks test ends up with a natural rhythm:

  1. Arrange: WebMock.StubRequest(...) calls that set up the responses your code under test will see.
  2. Act: call the code under test.
  3. Assert: your usual DUnitX Assert.AreEqual checks on the application-level behaviour, followed by WebMock.Assert.Get(...) / Post(...) / etc. checks on the HTTP traffic.

Together they cover both sides: did the code do the right thing internally, and did it talk to the network the way it should have.

What next?

That covers the basics of testing HTTP code with WebMocks in Delphi: setup, responses, request matching, and assertions. Enough for the HTTP layer of most Delphi applications.

There's more you can do once you're past the basics: testing OAuth and bearer-token flows, mocking AWS Signature V4 signed requests, simulating retry and rate-limit behaviour, using WebMocks in larger integration tests. If any of that would be useful, or you're stuck testing something specific with WebMocks and can't see how, get in touch. Enough interest and we'll do an advanced series.

WebMocks for Delphi is on GitHub, with demos for these articles in Delphi-WebMocks-Demos. Let me know what you build.