Skip to main content

Command Palette

Search for a command to run...

WireMock.Net vs MockHttp in ASP.NET Core: Which HTTP Mocking Approach Should Your Team Use?

Updated
โ€ข11 min read

Most ASP.NET Core services call external HTTP dependencies โ€” payment gateways, third-party APIs, internal microservices. Testing that behaviour without making real network calls is one of those problems every team handles differently, and the tooling choice turns out to matter a lot more than people expect. The two most common options in .NET are WireMock.Net (a full in-process HTTP stub server) and RichardSzalay.MockHttp (a lightweight HttpMessageHandler replacement). The concepts are related, but the trade-offs point different teams in different directions. For developers who want to see these approaches wired into a complete test suite alongside a production API, the full implementation โ€” including typed clients, fault injection, and retry policy testing โ€” is available on Patreon, with annotated source code that maps directly to what enterprise teams actually ship.

This decision sits squarely in the testing module of the ASP.NET Core Web API: Zero to Production course, which covers integration testing with WebApplicationFactory, Moq for mocking handlers, and the patterns that make tests resilient to infrastructure changes.

ASP.NET Core Web API: Zero to Production

What the Problem Actually Is

Every ASP.NET Core service that uses IHttpClientFactory or a typed client eventually needs tests that exercise code paths involving outbound HTTP. The instinct is to avoid real HTTP calls during testing โ€” they are slow, flaky, and introduce external dependencies that are outside your control. The challenge is that HttpClient is not straightforward to mock: you cannot simply Moq it because the methods that matter (SendAsync) are on the protected HttpMessageHandler, not the client surface itself.

Two approaches have become the practical standard:

  1. RichardSzalay.MockHttp โ€” replaces the HttpMessageHandler inside HttpClient with one that returns pre-programmed responses. The handler runs in-process, there is no network stack involved, and setup is done via a fluent API.

  2. WireMock.Net โ€” starts an actual HTTP server on a local port during the test. Your HttpClient makes real HTTP requests (over loopback) that hit WireMock's listener, which matches them against configured rules and returns stubbed responses.

The conceptual difference is significant: MockHttp is a handler-level interceptor; WireMock.Net is a network-level stub server.

RichardSzalay.MockHttp: Handler-Level Mocking

MockHttp works by replacing the message handler that HttpClient delegates to. When you configure a MockHttpMessageHandler, every call to SendAsync on the client goes through your stub instead of the network.

Why Teams Choose It

Speed is the primary argument. Because there is no actual I/O, MockHttp-based tests run significantly faster than anything involving a real server. For unit tests that cover a service layer method โ€” where the point is to verify your logic, not the HTTP infrastructure โ€” this is almost always the right level of abstraction.

Simplicity for typed client testing is the other driver. When your application registers a typed client via AddHttpClient<T>(), you can inject a MockHttpMessageHandler during test setup without touching the rest of the DI container. The registration overhead is low and the intent of the test is immediately readable.

No port management. MockHttp runs entirely in process. There are no port conflicts, no need to manage server lifecycle, and no timing issues around when the stub is ready to accept connections.

Where It Struggles

The fidelity gap becomes visible when you need to test HTTP-layer behaviour rather than application logic. MockHttp does not exercise real HTTP infrastructure โ€” it bypasses the network stack entirely. That means:

  • Retry policies tested with MockHttp may behave differently in production if the failure mode they are simulating does not actually map to how the real stack behaves (for example, connection timeouts vs. response timeouts have different trigger paths).
  • Connection pool behaviour, keepalive semantics, and chunked transfer encoding are not in the picture at all.
  • WireMock.Net allows you to test request matching in a way that is closer to how real servers respond โ€” including slow responses, partial responses, and connection drops.

WireMock.Net: Network-Level Stub Server

WireMock.Net starts an in-process HTTP listener on a configurable port. Your application's HttpClient (configured to target http://localhost:{port}) makes genuine HTTP calls, and WireMock returns the response you have configured for the matched route.

Why Teams Choose It

Highest-fidelity integration testing. Because the request traverses the full HTTP stack (including DNS resolution if you use localhost, TCP socket, HTTP/1.1 framing), the test exercises exactly the same code path as production. Retry policies, timeout cancellation, redirect handling, and header forwarding all behave as they would against a real server.

Request verification at the network level. WireMock captures every request it receives. You can assert on the exact headers, query parameters, body content, and verb that arrived at the stub โ€” which is useful when testing that your service correctly assembles outbound requests (correct Authorization header, correct Content-Type, correct Accept header).

Fault simulation. WireMock.Net supports configuring delayed responses, connection resets, and HTTP error codes in ways that naturally trigger timeout and circuit-breaker logic in Polly or AddStandardResilienceHandler(). Simulating a 503 that recovers after two retries is straightforward and the test exercises the actual Polly pipeline rather than a mock of it.

Multi-service simulation. A single WireMock instance can simulate multiple downstream endpoints by registering different route patterns. For integration tests that exercise a service which fans out to several APIs, WireMock lets you control all of them from one test fixture.

Where It Struggles

Test speed. Starting a TCP listener, even on loopback, is measurably slower than an in-process handler. For test suites with hundreds of tests, the overhead compounds. WireMock.Net supports a shared server instance across a test fixture to mitigate this, but it requires careful state reset between tests using ResetAsync().

Port management. In CI environments with parallelised test runners, each WireMock instance needs its own port. Using port 0 (let the OS assign an available port) and wiring that into the HttpClient base address is the recommended approach, but it adds configuration overhead.

Over-engineering for pure unit tests. If the test is verifying that your service transforms a response body correctly, MockHttp is a better fit โ€” WireMock adds infrastructure cost without providing additional value for that scenario.

Side-By-Side Comparison

Dimension MockHttp WireMock.Net
HTTP stack traversal None (in-process) Full (loopback TCP)
Test speed Fastest Slower (server startup cost)
Retry/resilience pipeline fidelity Partial Full
Setup complexity Low Medium
Port management Not required Required
Fault simulation Limited (status codes, exceptions) Rich (delays, drops, partial responses)
Request verification Handler-level Network-level
Best fit Unit tests, service-layer logic Integration tests, Polly pipelines
CI parallel test support Native Requires port-per-instance strategy

Is There a Third Option?

Some teams avoid both libraries and instead create a custom HttpMessageHandler implementation that they register directly โ€” a hand-rolled fake. This works, but it does not buy you the assertion and matching fluency of MockHttp, and it requires more boilerplate per test. The two library options cover the vast majority of real-world needs without requiring custom infrastructure.

Another pattern worth knowing is using WebApplicationFactory with a IHttpMessageHandlerFactory override โ€” this lets you inject MockHttp into the full ASP.NET Core pipeline, which is closer to integration testing than pure unit testing while retaining the speed of in-process mocking. This approach is covered in detail in the ASP.NET Core integration testing guide on Coding Droplets.

What Should Your Team Actually Use?

Use MockHttp when:

  • You are writing unit tests that cover a service class or handler
  • The test is about your logic (how you build the request, how you map the response), not about HTTP infrastructure
  • You need fast, isolated tests that run in a few milliseconds
  • Your typed clients are registered via IHttpClientFactory and you want to inject the mock handler cleanly

Use WireMock.Net when:

  • You are writing integration or end-to-end tests with WebApplicationFactory
  • The test needs to verify that Polly retry and circuit-breaker policies fire correctly under specific failure conditions
  • You need to assert on the exact HTTP request your service sends to an external API (headers, body, method)
  • You are testing timeout behaviour and need the TCP stack involved to trigger it correctly

Use MockHttp for unit test coverage of service-layer logic and typed client wrappers. Use WireMock.Net for a smaller suite of integration tests that exercise the full HTTP pipeline, especially around resilience policies. This gives you fast feedback on logic and confident coverage of the behaviour that matters most in production.

A single WireMock.Net fixture per test class โ€” reset between tests, shared server โ€” is the pattern that balances fidelity and performance. For the IHttpClientFactory setup patterns that make this work cleanly, the IHttpClientFactory enterprise guide is worth reading alongside this article.

Decision Matrix

Your situation Recommended approach
Unit testing a service that calls one API MockHttp
Integration test with WebApplicationFactory WireMock.Net
Testing Polly retry/circuit-breaker WireMock.Net
Testing request assembly (headers, body) WireMock.Net
CI pipeline with parallel test runs MockHttp (or WireMock.Net with port=0)
New project, greenfield API tests MockHttp to start; add WireMock.Net as the test suite matures
Legacy codebase with tight HttpClient coupling WireMock.Net (less refactoring needed)

โ˜• If this comparison was useful, buy us a coffee โ€” it helps keep the content coming!

FAQ

What is WireMock.Net and how does it differ from the Java WireMock?

WireMock.Net is a .NET port of the Java WireMock library, maintained as a first-class .NET package. It exposes a similar API โ€” request matching, response stubbing, request verification โ€” but runs as an in-process HTTP server rather than a standalone daemon. The .NET version does not require Java on the host and integrates naturally with xUnit or NUnit fixture lifecycle management.

Can MockHttp test timeout scenarios reliably?

MockHttp can simulate a delayed response using Task.Delay in a custom response builder, but because there is no actual TCP socket involved, the timeout behaviour depends on how the HttpClient.Timeout and CancellationToken propagation work at the handler level. For testing that a Polly timeout policy fires and is correctly surfaced to the caller, WireMock.Net's WithDelay() configuration is more representative of production behaviour.

Does WireMock.Net work with .NET 8 and .NET 10?

Yes. WireMock.Net targets .NET Standard 2.0 and above, which covers all currently supported .NET versions including .NET 8 and .NET 10. The library is actively maintained on GitHub under the wiremock/WireMock.Net organisation.

How do I reset WireMock.Net state between tests to prevent leakage?

Call server.ResetAsync() or server.Reset() in your test class's dispose method or an IAsyncLifetime.InitializeAsync() implementation. If tests share a single WireMock instance (recommended for performance), reset the stubs at the start of each test rather than recreating the server. This avoids startup overhead while guaranteeing a clean mapping table per test.

Can I use both MockHttp and WireMock.Net in the same test project?

Yes โ€” this is actually the recommended pattern for mature test suites. MockHttp lives in unit test projects where tests cover logic in isolation. WireMock.Net lives in integration test projects where the full ASP.NET Core pipeline is involved. Both packages are independent and do not conflict.

Should I mock HttpClient at the interface level instead of the handler level?

Wrapping HttpClient behind an interface (e.g., IExternalApiClient) is a valid design choice and makes unit testing trivial with any mocking framework like Moq or NSubstitute. The trade-off is that you are testing a mock of your own abstraction rather than testing the actual HTTP call path. For testing that the correct Authorization header is sent or that retry backoff is configured correctly, the handler-level and server-level approaches (MockHttp and WireMock.Net respectively) give you more confidence.

What NuGet packages do I need?

For MockHttp: RichardSzalay.MockHttp. For WireMock.Net: WireMock.Net. Both are available on NuGet and have no conflicting transitive dependencies in a standard ASP.NET Core project.

More from this blog

C

Coding Droplets

236 posts

Coding Droplets is your go-to resource for .NET and ASP.NET Core development. Whether you're just starting out or building production systems, you'll find practical guides, real-world patterns, and clear explanations that actually make sense.

From beginner-friendly tutorials to advanced architecture decisions. We publish fresh .NET content every day to help you grow at every stage of your career.