Level Up Your Integration Tests in .NET: Record, Replay, Relax

Author
By Giannis Georgopoulos ·

Sick of flaky integration tests?

You run your tests once — they pass. Run them again — they fail. Maybe the third-party API timed out. Or the response changed. Or your internet blinked. Integration tests should give you confidence, not stress.

That’s where deterministic integration testing comes in. Imagine recording your API interactions once and replaying them forever — offline, fast, and predictable.

No network. No surprises.

That’s exactly what Vcr.HttpRecorder does.

It’s inspired by the original Ruby VCR gem, revived for .NET and brought back to life with new features and bug fixes in my fork.

What Is Deterministic Integration Testing?

In traditional integration tests, you call real services — maybe a payment gateway, an external API, or even another microservice. But real services are unpredictable:

  • They might be slow or down.

  • Their responses might change.

  • They could rate-limit you.

This makes your tests flaky and slow. Worse, you can’t run them offline, and reproducing issues becomes a headache.

Deterministic integration testing solves this by recording the HTTP interactions during a real test run — just once — and saving them. On subsequent runs, instead of hitting the real service, it replays the recorded response. This means:

  • Your tests always get the same response.

  • They run faster.

  • You can run them offline.

  • They’re finally reliable.

Think of it like:

One real run to record
All future runs are just playback

This gives you the confidence of integration testing with much more speed and reliability — though not quite as fast as unit tests, it’s a massive improvement.

Why Not Just Use WireMock?

If you've done any HTTP-based integration testing in .NET, you've probably run into tools like:

  • WireMock.Net

  • MockHttpMessageHandler

  • TestServers and custom in-memory APIs

They’re powerful — but often overkill. You have to:

  • Define expected requests manually

  • Mock responses yourself

  • Keep your mocks in sync with reality

It's easy to end up testing your mocks instead of the real integration.

Vcr.HttpRecorder flips this around.

  • You run the test once, and it records the actual request and response.

  • No need to handcraft mocks or fake responses.

  • Next runs just replay that real interaction — safely and deterministically.

You can plug it into a specific HttpClient with a simple handler — or skip the plumbing entirely and have it automatically intercept all HTTP clients in your test environment.

Getting Started (The Easy Way)

The easiest way to use Vcr.HttpRecorder is to wrap your test in a recording context and let it automatically intercept all HTTP clients in your test environment. No manual plumbing, no special HttpClient setup.

using var context = new HttpRecorderContext((_, _) => new HttpRecorderConfiguration
{
    Mode = HttpRecorderMode.Auto, // Automatically records or replays
});

var client = webAppFactory.WithWebHostBuilder(builder =>
{
    builder.ConfigureTestServices(services =>
    {
        services.AddHttpRecorderContextSupport();
    });
}).CreateClient();

That’s it:

  • On the first run, it records real HTTP interactions into cassette files.

  • On subsequent runs, it replays them — fast and offline.

Cassette files(.har) are stored next to your tests by default and can be versioned with your repo. Want to update them? Just delete and re-record.

Prefer to wire it up manually? You can still use HttpRecorderHandler directly with specific clients — but most of the time, the automatic context is all you need.

What’s New in My Fork

The original Vcr.HttpRecorder was a solid idea — but it hadn’t been maintained and i got no responses from maintainers. I forked it to fix bugs, modernize it, and make it practical for real-world integration testing.

Here’s what I’ve added so far:

Concurrent context support
You can now run tests in parallel using HttpRecorderConcurrentContext, and each test will get its own isolated recording scope.

.NET 6/7/8 compatibility
Fixed support for newer .NET APIs like HttpClient.PostAsJsonAsync, GetFromJsonAsync, and others that were previously breaking the recorder.

Support for non-UTF8 responses
The original version assumed all responses were UTF-8, which caused crashes for binary or other encoded payloads. That’s now fixed.

Coming Soon

  • *Cassette diffing to understand what changed between recordings
  • Optional assertions on captured requests/responses

I’m building this based on actual needs from real-world projects. If you’ve got an idea or run into an edge case — open an issue or let’s talk!

Check out the repo

Give it a star if it helped !