HttpRecorder.Next
.NET HttpClient integration tests made easy.
HttpRecorder is an HttpMessageHandler that can record and replay HTTP interactions through the standard HttpClient . This allows the creation of HTTP integration tests that are fast, repeatable and reliable.
Interactions are recorded using the HTTP Archive format standard, so that they are easily manipulated by your favorite tool of choice.
Note: This is a modernized fork of the original HttpRecorder by nventive, maintained by Max Golovanov (max.golovanov+github@gmail.com). This fork features .NET 8 and .NET 9 support, updated dependencies, modern APIs, and compatibility fixes for the latest .NET ecosystem.

Getting Started
Install the package:
dotnet add package HttpRecorder.Next
# or, using Package Manager
Install-Package HttpRecorder.Next
Here is an example of an integration tests using HttpRecorder (the HttpRecorderDelegatingHandler):
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using HttpRecorder;
using Xunit;
namespace Sample
{
public class SampleIntegrationTests
{
[Fact]
public async Task ItShould()
{
var client = CreateHttpClient();
var response = await client.GetAsync("api/user");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
private HttpClient CreateHttpClient(
[CallerMemberName] string testName = "",
[CallerFilePath] string filePath = "")
{
var interactionFilePath = Path.Join(
Path.GetDirectoryName(filePath),
$"{Path.GetFileNameWithoutExtension(filePath)}Fixtures",
testName);
return new HttpClient(
new HttpRecorderDelegatingHandler(interactionFilePath) { InnerHandler = new HttpClientHandler() })
{
BaseAddress = new Uri("https://reqres.in/"),
};
}
}
}
Features
Record mode
The HttpRecorderDelegatingHandler can be run in different modes:
- Auto: Default mode - replay the interactions if the recording exists, otherwise record it.
- Record: Always record the interaction, even if a record is present.
- Replay: Always replay the interaction, throw if there is no recording.
- Passthrough: Always passes the request/response down the line, without any interaction
Just use the appropriate mode in the HttpRecorderDelegatingHandler constructor.
The mode can also be overridden using the environment variable HTTP_RECORDER_MODE.
If this is set to any valid HttpRecorderMode value, it will override the mode set in the code,
except if this mode is HttpRecorderMode.Passthrough.
This is useful when running in a CI environment and you want to make sure that no
request goes out and all interactions are properly committed to the codebase.
Customize the matching behavior
By default, matching of the recorded requests is done by comparing the HTTP Method and complete Request URI. The first request that match is used and will not be returned again in the current run.
If needed, the matching behavior can be customized using the RulesMatcher:
using HttpRecorder.Matchers;
var matcher = RulesMatcher.MatchOnce;
matcher = RulesMatcher.MatchOnce.ByHttpMethod();
matcher = RulesMatcher.MatchMultiple
.ByHttpMethod()
.ByRequestUri(UriPartial.Path)
.ByHeader("X-API-Key");
matcher = RulesMatcher.MatchOnce.By((request, message) => ...);
var client = new HttpClient(new HttpRecorderDelegatingHandler("...", matcher: matcher));
Additional customization can be done by providing a custom IRequestMatcher implementation.
Anonymize the records
Sometimes, there are portions of the requests / responses that you don't want recorded
(e.g. because of API keys you do not want to commit to the source code repo...).
In this case, you can use the RulesInteractionAnonymizer to perform the substitution.
using HttpRecorder.Anonymizers;
var anonymizer = RulesInteractionAnonymizer.Default
.AnonymizeRequestQueryStringParameter("queryStringParam")
.AnonymizeRequestHeader("requestHeader");
var client = new HttpClient(new HttpRecorderDelegatingHandler("...", anonymizer: anonymizer));
Additional customization can be done by providing a custom IInteractionAnonymizer
implementation.
HttpClientFactory
The component comes with extension methods for the HttpClientFactory:
services
.AddHttpClient("TheClient")
.AddHttpRecorder(interactionName);
Recorder Context
It is sometime helpful to be able to decoralate the injection of the HttpRecorderDelegatingHandler
and the Test case setup.
This is especially useful in the context of ASP.NET Core Integration tests.
It is possible to add the HttpRecorderDelegatingHandler globally to all HttpClient managed by the IHttpClientFactory,
and then to customize the recording in the test case by using the HttpRecorderContext.
Here is how to do it:
services.AddHttpRecorderContextSupport();
[Fact]
public async Task ItShould()
{
using var context = new HttpRecorderContext();
}
[Fact]
public async Task ItShould()
{
using var context = new HttpRecorderContext((sp, builder) =>
{
return builder.Name switch
{
nameof(TypedClient) => new HttpRecorderConfiguration
{
Matcher = RulesMatcher.MatchMultiple,
},
nameof(DisabledClient) => new HttpRecorderConfiguration
{
Enabled = false,
},
_ => null
};
});
}
Record interaction in external tools
Interaction files can be recorded using your favorite tool (e.g. Fiddler, Google Chrome Inspector, ...).
You only have to export it using the HAR/HTTP Archive format. They can then be used as-is as a test fixture that will be loaded by the HttpRecorderDelegatingHandler.
Customize the storage
Reading/writing the interaction can be customized by providing a custom IInteractionRepository implementation.
Changelog
Please consult the CHANGELOG for more information about version
history.
License
This project is licensed under the Apache 2.0 license - see the
LICENSE file for details.
Contributing
Please read CONTRIBUTING.md for details on the process for
contributing to this project.
Be mindful of our Code of Conduct.
Acknowledgments