3.65Configuring Assertion Logic

Created on Aug 17, 2026~17 min read

After enabling assertions, you can uniformly configure request assertions and response assertions through the Asserts(configure) method:

cs
HttpRequestBuilder.Get("https://furion.net")    .UseAssertions()    .Asserts(ast => ast        .RequestMethod(HttpMethod.Get)               // Request assertion        .ResponseStatusCode(200)                     // Response assertion        .ResponseHeaderExists("encoding")    );

Here, the ast parameter is of type HttpAssertionBuilder, which has a rich set of built-in assertion methods (custom extensions supported):

Request assertion methods (executed before sending)

  • RequestUri(expectedUri): asserts that the request URI equals the specified string
    • On failure, throws: Expected request URI to be '{expectedUri}', but found '{actual}'.
  • RequestMethod(expectedMethod): asserts that the HTTP method equals the specified HttpMethod
    • On failure, throws: Expected request method to be {expectedMethod}, but found {actual}.
  • RequestHeaderExists(name): asserts that the specified request header exists (including content headers)
    • On failure, throws: Expected request header '{name}' to exist, but it was not found.
  • RequestHeaderEquals(name, expectedValue): asserts that the first value of the request header strictly equals the specified string (case-sensitive)
    • On failure, throws: Expected request header '{name}' to be '{expectedValue}', but found '{actual}'.
  • RequestHeaderContains(name, expectedValue): asserts that any value of the request header contains the specified substring (case-insensitive)
    • On failure, throws: Expected request header '{name}' to contain '{expectedValue}', but the header was not found. or Expected request header '{name}' to contain '{expectedValue}', but actual values were: [{...}].
  • RequestContentContains(expectedSubstring): asserts that the request content contains the specified substring (case-insensitive)
    • On failure, throws: Expected request content to contain '{expectedSubstring}', but it was not found.
  • RequestContentEquals(expected): asserts that the request content completely equals the specified string
    • On failure, throws: Expected request content to be '{expected}', but found '{actual}'.
  • RequestSatisfies(assertion): custom request assertion (synchronous or asynchronous), directly operating on HttpRequestMessage
    • The asynchronous overload accepts Func<HttpRequestMessage, Task>.

Response assertion methods (executed after receiving the response)

  • AddAssertion(assertion): adds a custom assertion delegate (treated as a response assertion by default), such as ast.AddAssertion(async context => await ...).
  • ResponseStatusCode(statusCode): asserts that the response status code equals the specified value (an integer or HttpStatusCode)
    • On failure, throws: Expected response status code to be {expected}, but found {actual}.
  • ResponseStatusCodeIn(allowedStatusCodes): asserts that the status code is in the allowed list
    • On failure, throws: Expected response status code to be one of [{string.Join(", ", allowedStatusCodes)}], but found {actual}.
  • ResponseIsSuccessStatusCode(): asserts that the request succeeded (status code is 2xx)
    • On failure, throws: Expected response to be successful (2xx status code), but found status code {(int)context.StatusCode}.
  • ResponseContentContains(expectedSubstring): asserts that the response content contains the specified substring (case-insensitive)
    • On failure, throws: Expected response content to contain '{expectedSubstring}', but it was not found.
  • ResponseContentEquals(expected): asserts that the response content completely equals the specified string
    • On failure, throws: Expected response content to be '{expected}', but found '{content}'.
  • ResponseContentMatches(pattern): asserts that the response content matches the specified regular expression
    • On failure, throws: Expected response content to match regex '{pattern}', but it did not.
  • ResponseContentNotEmpty(): asserts that the response content is not empty
    • On failure, throws: Expected response content not to be empty.
  • ResponseHeaderExists(name): asserts that the specified response header exists (including content headers)
    • On failure, throws: Expected response header '{name}' to exist, but it was not found.
  • ResponseHeaderEquals(name, expectedValue): asserts that the first value of the response header strictly equals the specified string (case-sensitive)
    • On failure, throws: Expected response header '{name}' to be '{expectedValue}', but found '{actualValue}'.
  • ResponseHeaderContains(name, expectedValue): asserts that any value of the response header contains the specified substring (case-insensitive)
    • On failure, throws: Expected response header '{name}' to contain '{expectedValue}', but the header was not found. or Expected response header '{name}' to contain '{expectedValue}', but actual values were: [{string.Join(", ", values)}].
  • ResponseHeaderNotExists(name): asserts that the specified response header does not exist (including content headers)
    • On failure, throws: Expected response header '{name}' not to exist, but it was found.
  • ResponseDurationUnder(maxMilliseconds): asserts that the request elapsed time is under the specified number of milliseconds
    • On failure, throws: Expected response duration to be under {maxDuration.TotalMilliseconds:F2}ms, but it took {actualDuration.TotalMilliseconds:F2}ms.
  • ResponseSatisfies(assertion): custom response assertion (synchronous or asynchronous), directly operating on HttpResponseMessage
    • The asynchronous overload accepts Func<HttpResponseMessage, Task>.

Custom assertion methods

In addition to the built-in methods, you can add custom assertion logic to HttpAssertionBuilder through extension methods. For example, implement a ResponseIsJson method to verify whether the response content is of type application/json:

cs
public static class HttpAssertionBuilderExtensions{    public static HttpAssertionBuilder ResponseIsJson(this HttpAssertionBuilder httpAssertionBuilder)    {        return httpAssertionBuilder.AddAssertion(async context =>        {            var contentType = context.ResponseMessage?.Content?.Headers.ContentType?.MediaType;            const string jsonMediaType = "application/json";            // Allow "application/json" or "application/json; charset=utf-8" and similar            if (string.IsNullOrEmpty(contentType) ||                !contentType.StartsWith(jsonMediaType, StringComparison.OrdinalIgnoreCase))            {                await HttpAssertionException.ThrowAsync(                    $"Expected response Content-Type to be '{jsonMediaType}' (or a subtype with parameters), but found '{contentType}'.");            }        });    }}

Here, the context parameter is of type HttpAssertionContext, which contains the following properties and methods:

  • Properties:

    • RequestMessage: the sent request message (HttpRequestMessage?), available during the request assertion phase
    • ResponseMessage: the response message (HttpResponseMessage?), available during the response assertion phase
    • StatusCode: the response status code (of type HttpStatusCode)
    • IsSuccessStatusCode: whether the request succeeded (of type bool)
    • RequestDuration: the request elapsed time (milliseconds, of type long)
    • ServiceProvider: the service provider (of type IServiceProvider)
  • Methods:

    • ReadResponseAsStringAsync(): reads the response content string (automatically cached, can be read multiple times)
    • ReadRequestAsStringAsync(): reads the request content string (automatically cached, can be read multiple times)

Example of using a custom method:

cs
HttpRequestBuilder.Get("https://furion.net")    .UseAssertions()    .Asserts(ast => ast.ResponseIsJson().ResponseStatusCode(200));      // Chained calls supported

Using C# extension methods, you can flexibly extend the functionality of HttpAssertionBuilder, improving the maintainability and reusability of the code.