HttpRequest.Spy
1.0.10
dotnet add package HttpRequest.Spy --version 1.0.10
NuGet\Install-Package HttpRequest.Spy -Version 1.0.10
<PackageReference Include="HttpRequest.Spy" Version="1.0.10" />
paket add HttpRequest.Spy --version 1.0.10
#r "nuget: HttpRequest.Spy, 1.0.10"
// Install HttpRequest.Spy as a Cake Addin #addin nuget:?package=HttpRequest.Spy&version=1.0.10 // Install HttpRequest.Spy as a Cake Tool #tool nuget:?package=HttpRequest.Spy&version=1.0.10
HttpRequestSpy
HttpRequestSpy
is a tool aiming to test outgoing HttpRequest sent via an HttpClient.
It compares all sent http requests to an expected request definition and provides a user friendly error message when no recorded httprequest matches the expected one.
This tool is useful when you want to test your outgoing http requests but you don't want to mock the http client.
Installation
dotnet add package HttpRequest.Spy
Usage
[Fact]
public async Task HttpRequest_should_be_sent()
{
// Arrange
var spy = HttpRequestSpy.Create();
using var httpClient = new HttpClient(new SpyHttpMessageHandler(spy));
var instance = new TypedHttpClient(httpClient);
// Act
await instance.MakeHttpRequest();
// Assert
spy.HasRecordedRequests(1);
spy.AGetRequestTo("/some/ressource")
.WithQuery(new {
id = "12"
})
.OccurredOnce();
}
public class TypedHttpClient(HttpClient httpClient) {
public async Task<HttpResponseMessage> MakeHttpRequest() {
return await httpClient.GetAsync("/some/ressource?id=12");
}
}
Features
Fluent API
The HttpRequestSpy
provides a fluent API to help you define your expected http request.
spy.AGetRequestTo("/some/ressource")
.WithQuery(new {
id = "12"
})
.OccurredOnce();
User friendly error messages
One of the main idea behind this tool is to provide a user friendly error message when no recorded http request matches the expected one.
spy.APostRequestTo("/some/resource")
.WithJsonPayload(new {
prop1 = 1
})
.WithQuery(new {
id = "12"
})
.OccurredOnce();
⚠ Unexpected number of recorded requests matching expectations. Expected : 1. Actual : 0
Expectations:
✔ Method : POST
✔ Expected URL : /some/resource
✔ Payload : {"prop1":1}
✔ Query { id = 12 }
2 Recorded requests:
0/ GET http://domain/path/to/resource
⚠ HttpMethod does not match:
- Expected : POST
- Actual : GET
⚠ URL does not match:
- Expected : /some/resource
- Actual : /path/to/resource
⚠ Payload is empty:
- Expected : {"prop1":1}
- Actual : [null]
⚠ Query does not match :
-> Missing property $.id
1/ POST http://domain/path/to/resource
⚠ URL does not match:
- Expected : /some/resource
- Actual : /path/to/resource
⚠ Payload is empty:
- Expected : {"prop1":1}
- Actual : [null]
⚠ Query does not match :
-> Missing property $.id
Occurrences
You can define the number of occurences of your expected request.
spy.AGetRequestTo("/some/ressource")
.OccurredOnce();
spy.AGetRequestTo("/some/ressource")
.OccurredTwice();
spy.AGetRequestTo("/some/ressource")
.Occurred(3);
spy.AGetRequestTo("/some/ressource")
.NeverOccurred();
Number of overall recorded requests
You can define the number of overall recorded requests.
spy.HasRecordedRequests(5);
This codes checks that 5 requests have been recorded regardless of the content of the requests.
Absolute path and relative url
You can define the absolute path or the relative url of your expected request.
spy.AGetRequestTo("/some/ressource")
.OccurredOnce();
spy.AGetRequestTo("https://myapi.com/some/ressource")
.OccurredOnce();
GET, POST, PUT, DELETE, PATCH http verbs
You can define the http verb of your expected request.
spy.AGetRequestTo("/some/ressource")
.OccurredOnce();
spy.APostRequestTo("/some/ressource")
.OccurredOnce();
spy.APutRequestTo("/some/ressource")
.OccurredOnce();
spy.APatchRequestTo("/some/ressource")
.OccurredOnce();
spy.ADeleteRequestTo("/some/ressource")
.OccurredOnce();
Query parameters
You can define the query parameters of your expected request as an anonymous object.
spy.AGetRequestTo("/some/ressource")
.WithQuery(new {
id = "12",
date = "2024-01-05"
})
/// Or
.WithQuery("id=12&date=2024-01-05")
/// Or
.WithQueryParam("id", "12")
.WithQueryParam("date", "2024-01-05")
.OccurredOnce();
Body / Payload
Only for POST, PUT, PATCH requests
You can define the body of your expected request as an anonymous object or target a specific property.
Note: payloads are compared using a custom comparison tool that will do a deep equal and returns all the mismatching properties. See the Comparison folder.
Note 2 : By default, in the error message the payload of the recorded request won't be displayed because it would create a too long message. We only display the mismatching properties. Sometimes, for debugging purpose, you might want to display the full payload. To do so, you can pass
true
to thelogRecordedRequestPayload
parameter.
Check Json payload
See HttpRequestSpyWhenJsonPayloadShould.cs file for all use cases.
spy.APostRequestTo("/some/ressource")
.WithJsonPayload(new
{
prop1 = 1,
prop2 = "value",
subProp = new
{
subProp1 = "subValue"
}
})
// Or
.WithJsonPayloadProperty("prop1") // Will check that the property exists
.WithJsonPayloadProperty("prop1", 1)
.WithJsonPayloadProperty("prop2", "value")
.WithJsonPayloadProperty("subProp", new
{
subProp1 = "subValue"
})
.OccurredOnce();
Note 1 : To compare payloads we use System.Text.Json. It is possible to pass a custom JsonSerializerOptions to the WithJsonPayloadProperty and WithJsonPayload methods.
Note 2: We're not considering using Newtonsoft.Json at all and it is not possible to change the serializer.
Json payload matching JsonSchema
Using JsonSchema, you can check that the payload matches a specific schema.
spy.APostRequestTo("/some/ressource")
.WithPayloadMatchingJsonSchema("path/to/schema.json")
.OccurredOnce();
Note: it is also possible to specify the schema as a string.
Check Xml payload
See HttpRequestSpyWhenXmlPayloadShould.cs file for all use cases.
spy.APostRequestTo("/some/ressource")
.WithXmlPayload(new
{
prop1 = 1,
prop2 = "value",
subProp = new
{
subProp1 = "subValue"
}
})
// Or
.WithXmlPayloadProperty("/_x003F_anonymous_x003F_/prop1") // Will check that the property exists
.WithXmlPayloadProperty("/_x003F_anonymous_x003F_/prop1", 1)
.WithXmlPayloadProperty("/_x003F_anonymous_x003F_/prop2", "value")
.WithXmlPayloadProperty("/_x003F_anonymous_x003F_/subProp", new
{
subProp1 = "subValue"
})
// Or :
.WithXmlPayloadProperty("/_x003F_anonymous_x003F_/subProp/subProp1", "subValue")
.OccurredOnce();
Note 1: the xpath used is a simplified xpath. It is not a full xpath implementation. It ignores namespaces and attributes for readability purpose. We do not need such complex features.
Note 2: in a future version, we might ignore the type node for anonymous objects.
Note 3: XSD validation is not supported yet.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. |
-
net8.0
- JsonSchema.Net (>= 7.2.3)
-
net9.0
- JsonSchema.Net (>= 7.2.3)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on HttpRequest.Spy:
Package | Downloads |
---|---|
sas.simulators.http
Includes objects and helpers to create HttpClient simulators easily when using the Scenario/API/Simulators concept. |
|
sas.simulators.soap
Experimental, not production-ready yet. |
GitHub repositories
This package is not used by any popular GitHub repositories.