Swevo.HttpClient.TestKit
1.0.1
Prefix Reserved
dotnet add package Swevo.HttpClient.TestKit --version 1.0.1
NuGet\Install-Package Swevo.HttpClient.TestKit -Version 1.0.1
<PackageReference Include="Swevo.HttpClient.TestKit" Version="1.0.1" />
<PackageVersion Include="Swevo.HttpClient.TestKit" Version="1.0.1" />
<PackageReference Include="Swevo.HttpClient.TestKit" />
paket add Swevo.HttpClient.TestKit --version 1.0.1
#r "nuget: Swevo.HttpClient.TestKit, 1.0.1"
#:package Swevo.HttpClient.TestKit@1.0.1
#addin nuget:?package=Swevo.HttpClient.TestKit&version=1.0.1
#tool nuget:?package=Swevo.HttpClient.TestKit&version=1.0.1
Swevo.HttpClient.TestKit
Unit-test HttpClient calls without mocking frameworks. Fluent setup, JSON responses, request recording, and built-in verification. Zero dependencies.
var handler = new FakeHttpMessageHandler();
handler.SetupGet("https://api.example.com/users")
.ReturnsJson(new[] { new User(1, "Alice") });
handler.SetupPost("https://api.example.com/users")
.ReturnsJson(new User(2, "Bob"), HttpStatusCode.Created);
var client = new HttpClient(handler);
// Act
var users = await client.GetFromJsonAsync<User[]>("https://api.example.com/users");
// Verify
users.Should().ContainSingle(u => u.Name == "Alice");
handler.VerifyGetWasCalled("https://api.example.com/users");
handler.VerifyPostNeverCalled("https://api.example.com/users");
Install
dotnet add package Swevo.HttpClient.TestKit
Why not Moq?
| Moq | Swevo.HttpClient.TestKit |
|
|---|---|---|
| Dependencies | Moq + Castle.Core | Zero |
| Setup syntax | mock.Protected().Setup<Task<HttpResponseMessage>>("SendAsync", ...) |
handler.SetupGet(url).ReturnsJson(...) |
| JSON responses | Manual | ReturnsJson<T>(value) |
| Request recording | Manual | handler.RecordedRequests |
| Verification | mock.Verify(...) |
handler.VerifyGetWasCalled(url) |
Setup methods
handler.SetupGet(url)
handler.SetupPost(url)
handler.SetupPut(url)
handler.SetupPatch(url)
handler.SetupDelete(url)
handler.Setup(HttpMethod.Options, url) // any method
Response builders
.ReturnsJson(value) // 200 OK + application/json body
.ReturnsJson(value, HttpStatusCode.Created) // 201 Created + application/json body
.ReturnsString("OK") // 200 OK + text/plain body
.ReturnsString("Bad Request", HttpStatusCode.BadRequest)
.ReturnsStatusCode(HttpStatusCode.NoContent) // no body
.Returns(response) // fixed HttpResponseMessage
.Returns(req => BuildResponse(req)) // factory — receives the original request
.Throws(new HttpRequestException("timeout")) // throws on request
Request recording
// All requests in order
handler.RecordedRequests.Should().HaveCount(3);
// Custom assertions
handler.RecordedRequests
.Should().ContainSingle(r =>
r.Method == HttpMethod.Post &&
r.RequestUri!.PathAndQuery == "/users");
Verification
handler.VerifyWasCalled(HttpMethod.Get, url); // called ≥ 1 time
handler.VerifyNeverCalled(HttpMethod.Delete, url); // called 0 times
handler.VerifyCalledTimes(HttpMethod.Get, url, 3); // called exactly 3 times
// Convenience
handler.VerifyGetWasCalled(url);
handler.VerifyPostWasCalled(url);
handler.VerifyPutWasCalled(url);
handler.VerifyPatchWasCalled(url);
handler.VerifyDeleteWasCalled(url);
handler.VerifyGetNeverCalled(url);
handler.VerifyPostNeverCalled(url);
handler.VerifyDeleteNeverCalled(url);
Verification methods throw InvalidOperationException on failure — compatible with any test framework.
Unmatched requests
By default, unmatched requests return 404 Not Found. Override to use strict mode:
handler.UnmatchedRequestHandler = req =>
throw new InvalidOperationException($"Unexpected request: {req.Method} {req.RequestUri}");
URL matching
- Exact string match, case-insensitive
- If the same method+URL is set up twice, the last setup wins
- Query strings are part of the URL — include them in the setup if needed
Testing a typed HttpClient
public class UserService(HttpClient client)
{
public Task<User[]> GetUsersAsync() =>
client.GetFromJsonAsync<User[]>("/users")!;
}
// Test
var handler = new FakeHttpMessageHandler();
handler.SetupGet("https://api.example.com/users")
.ReturnsJson(new[] { new User(1, "Alice") });
var client = new HttpClient(handler) { BaseAddress = new Uri("https://api.example.com") };
var sut = new UserService(client);
var users = await sut.GetUsersAsync();
users.Should().HaveCount(1);
Part of the Swevo testing toolkit
| Package | Purpose |
|---|---|
| Swevo.HttpClient.TestKit | This package |
| Swevo.MassTransit.TestKit | Fake MassTransit request clients |
License
MIT © 2026 Justin Bannister
| 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 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.0.0: FakeHttpMessageHandler with SetupGet/Post/Put/Patch/Delete, ReturnsJson/String/StatusCode, RecordedRequests, VerifyWasCalled/VerifyNeverCalled/VerifyCalledTimes.