Skip to main content

HTTP requests and responses

Describes the possible expectations for HttpRequestMessage and HttpResponseMessage.

Expectations for HttpRequestMessage:

ExpectationNegatedSummary
HasMethodhas the expected HTTP method
HasRequestUrihas the expected request URI
HasHeaderDoesNotHaveHeaderhas a header, optionally with a value
HasContenthas the expected string content

Expectations for HttpResponseMessage:

ExpectationNegatedSummary
HasStatusCodeHasStatusCode().DifferentTohas the expected status code or status category
HasHeaderDoesNotHaveHeaderhas a header, optionally with a value
HasContentTypehas the expected media type
HasContenthas the expected string content
HasProblemDetailsContenthas a ProblemDetails content
HasRequestMessagethe request message meets nested expectations

HttpRequestMessage​

Method​

You can verify that the HttpRequestMessage has the expected method:

HttpRequestMessage request = new(HttpMethod.Get, "https://music.example.com/tracks/1");

await Expect.That(request).HasMethod(HttpMethod.Get);

Request URI​

You can verify that the HttpRequestMessage has the expected request URI:

HttpRequestMessage request = new(HttpMethod.Get, "https://music.example.com/tracks/1");

await Expect.That(request).HasRequestUri("https://music.example.com/tracks/1");
await Expect.That(request).HasRequestUri(new Uri("https://music.example.com/tracks/1"));

Request headers​

You can verify that the HttpRequestMessage has a header, optionally with the expected value, or that it does not have it:

HttpRequestMessage request = new(HttpMethod.Get, "https://music.example.com/tracks/1");
request.Headers.Add("Accept", "application/json");

await Expect.That(request).HasHeader("Accept");
await Expect.That(request).HasHeader("Accept").WithValue("application/json");
await Expect.That(request).DoesNotHaveHeader("Authorization");

WithValue supports the same string options and match types as comparing strings.

When the header has multiple values, WithValues verifies that it has exactly these values in the same order:

HttpRequestMessage request = new(HttpMethod.Get, "https://music.example.com/tracks/1");
request.Headers.Add("Accept", ["application/json", "text/plain"]);

await Expect.That(request).HasHeader("Accept").WithValues("application/json", "text/plain");

WithValues supports the same string options, match types and collection options as comparing string collections, e.g. .WithValues("text/plain", "application/json").InAnyOrder().IgnoringCase().

You can also add expectations on the header value or on all of its values:

HttpRequestMessage request = new(HttpMethod.Get, "https://music.example.com/tracks/1");
request.Headers.Add("Accept-Encoding", ["gzip", "deflate"]);

await Expect.That(request).HasHeader("Accept-Encoding")
.WhoseValues(values => values.Contains("gzip"));

The failure message shows the difference and the request:

HttpRequestMessage request = new(HttpMethod.Get, "https://music.example.com/tracks/1");
request.Headers.Add("Cache-Control", "no-cache");

await Expect.That(request).HasHeader("Cache-Control").WithValue("max-age=0");
Failure message
Expected that request
has a "Cache-Control" header whose value is equal to "max-age=0",
but it had header value "no-cache", which differs at index 0:
↓ (actual)
"no-cache"
"max-age=0"
↑ (expected)

HTTP-Request:
GET https://music.example.com/tracks/1 HTTP/1.1
Cache-Control: no-cache

Request content​

You can verify that the HttpRequestMessage has the expected string content:

HttpRequestMessage request = new(HttpMethod.Post, "https://music.example.com/tracks")
{
Content = new StringContent("{\"title\": \"Let It Be\"}"),
};

await Expect.That(request).HasContent("*Let It Be*").AsWildcard();
await Expect.That(request).HasContent(content => content.Contains("Let It Be"));

The content supports the same string options and match types as comparing strings.

HttpResponseMessage​

Status code​

You can verify the status code of the HttpResponseMessage, either the exact value or its category:

HttpResponseMessage response = await httpClient.GetAsync("https://music.example.com/tracks/1");

await Expect.That(response).HasStatusCode(HttpStatusCode.OK);
await Expect.That(response).HasStatusCode().EqualTo(HttpStatusCode.OK);
await Expect.That(response).HasStatusCode().DifferentTo(HttpStatusCode.NotFound);
await Expect.That(response).HasStatusCode().Success();

The categories are Success() (2xx), Redirection() (3xx), ClientError() (4xx), ServerError() (5xx) and Error() (4xx or 5xx). Combine them with .Or to allow several:

HttpResponseMessage response = await httpClient.PostAsync("https://music.example.com/tracks", new StringContent(""));

await Expect.That(response).HasStatusCode().ClientError().Or.HasStatusCode().ServerError();

A failing expectation against a test server

HttpResponseMessage response = await httpClient.GetAsync("/tracks/1");

await Expect.That(response).HasStatusCode(HttpStatusCode.NotFound);

fails with the request and the response:

Failure message
Expected that response
has status code 404 NotFound,
but it had status code 200 OK

HTTP-Request:
GET http://localhost/tracks/1 HTTP/1.1

HTTP-Response:
200 OK HTTP/1.1
x-vendor: VENDOR
Content-Type: application/json; charset=utf-8
Content-Length: 51
{
"id": 1,
"title": "Let It Be",
"artist": "The Beatles"
}

Response headers​

You can verify that the HttpResponseMessage has a header, optionally with the expected value, or that it does not have it:

HttpResponseMessage response = await httpClient.GetAsync("https://music.example.com/tracks/1");

await Expect.That(response).HasHeader("Cache-Control");
await Expect.That(response).HasHeader("Cache-Control").WithValue("must-revalidate, max-age=0, private");
await Expect.That(response).DoesNotHaveHeader("Set-Cookie");

When the header has multiple values, WithValues verifies that it has exactly these values in the same order:

HttpResponseMessage response = await httpClient.GetAsync("https://music.example.com/tracks/1");

await Expect.That(response).HasHeader("Vary").WithValues("Accept", "Accept-Encoding");

WithValues supports the same string options, match types and collection options as comparing string collections, e.g. .WithValues("text/plain", "application/json").InAnyOrder().IgnoringCase().

You can also add expectations on the header value or on all of its values:

HttpResponseMessage response = await httpClient.GetAsync("https://music.example.com/tracks/1");

await Expect.That(response).HasHeader("ETag")
.WhoseValue(value => value.IsNotEmpty());
await Expect.That(response).HasHeader("Vary")
.WhoseValues(values => values.Contains("Accept-Encoding"));

Content type​

You can verify the media type in the Content-Type header of the HttpResponseMessage:

HttpResponseMessage response = await httpClient.GetAsync("/tracks/1");

await Expect.That(response).HasContentType("application/json");
await Expect.That(response).HasContentType("application/*").AsWildcard();

For example, expecting plain text from an endpoint that returns JSON

HttpResponseMessage response = await httpClient.GetAsync("/tracks/1");

await Expect.That(response).HasContentType("text/plain");

fails with the difference, the request and the response:

Failure message
Expected that response
has a `Content-Type` header equal to "text/plain",
but it had content type "application/json", which differs at index 0:
↓ (actual)
"application/json"
"text/plain"
↑ (expected)

HTTP-Request:
GET http://localhost/tracks/1 HTTP/1.1

HTTP-Response:
200 OK HTTP/1.1
x-vendor: VENDOR
Content-Type: application/json; charset=utf-8
Content-Length: 51
{
"id": 1,
"title": "Let It Be",
"artist": "The Beatles"
}

Response content​

You can verify that the HttpResponseMessage has the expected string content:

HttpResponseMessage response = await httpClient.GetAsync("https://music.example.com/tracks/1");

await Expect.That(response).HasContent("*Let It Be*").AsWildcard();
await Expect.That(response).HasContent(content => content.Contains("The Beatles"));

The content supports the same string options and match types as comparing strings. With aweXpect.Json, the nested expectations can also verify JSON content:

HttpResponseMessage response = await httpClient.GetAsync("https://music.example.com/tracks/1");

await Expect.That(response).HasContent(content => content
.IsValidJsonMatching(new { title = "Let It Be", artist = "The Beatles" }));

Problem details​

You can verify that the content of the HttpResponseMessage is a valid ProblemDetails object, optionally with the expected type, title, status, detail and instance:

HttpResponseMessage response = await httpClient.GetAsync("https://music.example.com/tracks/42");

await Expect.That(response)
.HasProblemDetailsContent("https://httpstatuses.com/404")
.WithTitle("Track not found")
.WithStatus(404)
.WithInstance("/tracks/42");

The type, title, detail and instance support the same string options and match types as comparing strings.

Request message​

You can add expectations on the HttpRequestMessage that led to the HttpResponseMessage:

HttpResponseMessage response = await httpClient.GetAsync("https://music.example.com/tracks/1");

await Expect.That(response).HasRequestMessage(request => request
.HasMethod(HttpMethod.Get).And
.HasRequestUri("https://music.example.com/tracks/1"));