3.65Configuring Assertion Logic
After enabling assertions, you can uniformly configure request assertions and response assertions through the Asserts(configure) method:
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 requestURIequals the specified string- On failure, throws:
Expected request URI to be '{expectedUri}', but found '{actual}'.
- On failure, throws:
RequestMethod(expectedMethod): asserts that theHTTPmethod equals the specifiedHttpMethod- On failure, throws:
Expected request method to be {expectedMethod}, but found {actual}.
- On failure, throws:
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.
- On failure, throws:
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}'.
- On failure, throws:
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.orExpected request header '{name}' to contain '{expectedValue}', but actual values were: [{...}].
- On failure, throws:
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.
- On failure, throws:
RequestContentEquals(expected): asserts that the request content completely equals the specified string- On failure, throws:
Expected request content to be '{expected}', but found '{actual}'.
- On failure, throws:
RequestSatisfies(assertion): custom request assertion (synchronous or asynchronous), directly operating onHttpRequestMessage- The asynchronous overload accepts
Func<HttpRequestMessage, Task>.
- The asynchronous overload accepts
Response assertion methods (executed after receiving the response)
AddAssertion(assertion): adds a custom assertion delegate (treated as a response assertion by default), such asast.AddAssertion(async context => await ...).ResponseStatusCode(statusCode): asserts that the response status code equals the specified value (an integer orHttpStatusCode)- On failure, throws:
Expected response status code to be {expected}, but found {actual}.
- On failure, throws:
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}.
- On failure, throws:
ResponseIsSuccessStatusCode(): asserts that the request succeeded (status code is2xx)- On failure, throws:
Expected response to be successful (2xx status code), but found status code {(int)context.StatusCode}.
- On failure, throws:
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.
- On failure, throws:
ResponseContentEquals(expected): asserts that the response content completely equals the specified string- On failure, throws:
Expected response content to be '{expected}', but found '{content}'.
- On failure, throws:
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.
- On failure, throws:
ResponseContentNotEmpty(): asserts that the response content is not empty- On failure, throws:
Expected response content not to be empty.
- On failure, throws:
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.
- On failure, throws:
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}'.
- On failure, throws:
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.orExpected response header '{name}' to contain '{expectedValue}', but actual values were: [{string.Join(", ", values)}].
- On failure, throws:
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.
- On failure, throws:
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.
- On failure, throws:
ResponseSatisfies(assertion): custom response assertion (synchronous or asynchronous), directly operating onHttpResponseMessage- The asynchronous overload accepts
Func<HttpResponseMessage, Task>.
- The asynchronous overload accepts
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:
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 phaseResponseMessage: the response message (HttpResponseMessage?), available during the response assertion phaseStatusCode: the response status code (of typeHttpStatusCode)IsSuccessStatusCode: whether the request succeeded (of typebool)RequestDuration: the request elapsed time (milliseconds, of typelong)ServiceProvider: the service provider (of typeIServiceProvider)
-
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:
HttpRequestBuilder.Get("https://furion.net") .UseAssertions() .Asserts(ast => ast.ResponseIsJson().ResponseStatusCode(200)); // Chained calls supportedUsing C# extension methods, you can flexibly extend the functionality of HttpAssertionBuilder, improving the maintainability and reusability of the code.