How to Use External HTTP API Mocking in .NET Integration Tests?

Seldom do applications operate alone. To fulfilll a request, an ASP.NET Core API may contact an identity provider, an inventory service, a payment gateway, or another internal API.

The reliability of integration tests may be compromised by these additional dependencies. If an external system produces different data than anticipated, a network connection times out, or a remote service is unavailable, the test may fail. Additionally, if tests use real accounts or initiate real transactions, they may become costly or dangerous.

In .NET, you can replace the underlying HttpMessageHandler used by HttpClient with a controlled test implementation. This approach works with IHttpClientFactory and typed HTTP clients, allowing you to test application behavior while keeping real database and ASP.NET Core components in the test pipeline.

Why Mock External APIs in Integration Tests?

Consider an order API that checks inventory before confirming an order. Its service calls an external inventory endpoint to determine whether a product is available.

A test that calls the real inventory service depends on several things outside the application:

  • The external service must be available.
  • Network communication must succeed.
  • Test credentials must remain valid.
  • The returned data must match the test’s expectations.
  • The request must not cause unintended changes in a real environment.

A mock removes these dependencies. The test can specify the response that the inventory service should return and verify how the application handles it.

Mocking is particularly useful for testing scenarios that are difficult to reproduce with a real service, such as HTTP 429 rate limits, HTTP 500 errors, malformed JSON, and slow responses.

However, mocking should not replace every test involving HTTP. You should still use separate tests when you need to verify actual authentication configuration, network behavior, or compatibility with a real external service.

Create a Typed HTTP Client

Start with a small service that calls an external API. In this example, the application retrieves product details from an inventory service.

The client receives an HttpClient through its constructor. It sends a GET request, checks the response status, and deserializes the JSON response into an InventoryItem.

The cancellation token allows the caller to cancel the HTTP operation and response processing.

Register the typed client in the application’s service container:

The example address is a placeholder. In production, configure the actual service address through application configuration.

Using a typed client keeps HTTP-related code separate from controllers and makes it easier to replace the HTTP transport in tests.

Mock HttpMessageHandler

HttpClient sends requests through an HttpMessageHandler. By supplying a custom handler, a test can return a predefined response without making a real network request.

Create a test handler that returns JSON:

This handler returns a successful response for product ID 10 and a 404 response for other paths.

The handler does not contact an external service. It intercepts the request inside the test process and creates an HTTP response directly.

For a small test suite, a dedicated handler like this can be enough. For more complex scenarios, you can build a configurable handler that supports different response codes, request matching, delays, and captured request details.

Write an Integration Test with WebApplicationFactory

Unit-testing InventoryClient alone can verify its HTTP behavior, but an integration test should also exercise the ASP.NET Core application pipeline.

The Microsoft.AspNetCore.Mvc.Testing package provides WebApplicationFactory<TEntryPoint>, which starts the application in a test host. You can override its service configuration to replace the external HTTP handler.

The following example assumes the application exposes an endpoint that uses InventoryClient and returns the retrieved item.

First, create a factory that registers the fake handler:

The example uses the typed client registration in the test host to configure the fake primary handler. If the production registration includes additional settings, such as a base address, authentication, or delegating handlers, preserve or explicitly configure the settings required by the test.

For applications that need to replace an existing typed-client registration, inspect the service registrations and remove or override the relevant registration deliberately. Avoid leaving two conflicting registrations and assuming the intended one will always be selected.

Next, write a test using xUnit:

This test sends an HTTP request through the application’s test server. When the endpoint calls InventoryClient, the fake handler supplies the inventory response.

The test verifies the application-level result rather than only checking the HTTP client in isolation.

For this example to compile, the application must define an endpoint at /api/products/{id} that calls InventoryClient, and Program must be accessible to the test project. A common approach is to add public partial class Program { } to the application entry-point file when required by the test project.

Test External API Failures

A successful response is only one part of an HTTP integration test suite. External services can return errors, and your application should respond predictably.

For example, you can create a handler that always returns a server error:

Because InventoryClient calls EnsureSuccessStatusCode(), a 503 response causes an HttpRequestException.

A test can verify that behavior directly:

This is a focused test of the HTTP client rather than a full application integration test. Both styles are useful: client tests cover request and response handling, while application integration tests verify how controllers, services, and middleware work together.

If your application translates external service failures into domain-specific responses, test that translation too. For example, a controller might return a 503 response to its caller rather than exposing an unhandled exception.

Verify That the Application Sends the Correct Request

A fake handler can also inspect incoming requests. This helps test query parameters, HTTP methods, headers, and request bodies.

For example, an API may require a specific authorization header. A test handler can capture the request and verify that the expected header is present.

Do not put real API keys or production credentials in tests. Use dummy credentials and a controlled test configuration.

For more complex HTTP behavior, a dedicated mocking library can provide request matching and response setup with less custom code. Choose a tool that makes the test readable and does not obscure which request is expected or which response should be returned.

Regardless of the library, verify both sides of the interaction: the application sends the intended request, and it handles the returned response correctly.

Common Mistakes When Mocking HTTP APIs

Accidentally making real network requests

If the fake handler is not registered for the client used by the application, the test may still use the production HTTP configuration.

Make the test configuration explicit and ensure the relevant typed client uses the fake handler.

Testing only the successful response

External APIs can return errors, time out, or provide unexpected data. Include tests for non-success status codes, invalid JSON, and cancellation where those cases matter to the application.

Mocking too much of the application

If every service and repository is replaced with a mock, the test may no longer verify meaningful application integration.

Keep the ASP.NET Core pipeline and the components you want to test real. Replace only the external dependency that needs to be isolated.

Assuming a fake handler tests network behavior

A fake HttpMessageHandler does not test DNS resolution, TLS negotiation, real connection pooling, or the external service’s behavior.

Use appropriate staging or contract tests when you need confidence in those areas.

Sharing mutable fake state between parallel tests

A handler that stores requests or changes its response based on previous calls can cause tests to interfere with one another if it is shared.

Keep test state isolated, reset it deliberately, or create a separate handler for each test when necessary.

Best Practices for Reliable HTTP Integration Tests

Use typed HTTP clients to keep external API logic separate from application endpoints. Configure test handlers explicitly, and use predictable responses that describe the scenario under test.

Test successful responses, error responses, request cancellation, and malformed payloads when relevant. Avoid depending on a live external service for ordinary automated integration tests.

Keep the application pipeline real enough to verify the behavior you care about. A test that exercises the routing, dependency injection, service layer, and response mapping provides more confidence than a test that only invokes a method directly.

Finally, remember that mocks verify your application’s assumptions about an external API. They do not prove that the external API still follows those assumptions. Add contract checks or targeted tests against a controlled environment when compatibility is important.

Conclusion

Mocking external HTTP APIs in .NET makes integration tests faster, more predictable, and easier to repeat. Replacing HttpMessageHandler allows you to control HTTP responses while keeping the rest of the ASP.NET Core application available for testing.

Use typed clients, configure fake handlers through the test host, and verify both successful responses and failure scenarios. Keep real network tests separate from ordinary integration tests so each test has a clear purpose.

With this approach, you can test how your application behaves when external services succeed, fail, or return unexpected data without making your entire test suite depend on their availability.

Recommendation for ASP.NET 11.0 Hosting

A solid base for developing online services and applications is ASP.NET Core 11. Before creating an ASP.NET web application, you must be proficient in JavaScript, HTML, CSS, and C#. There are thousands of web hosting providers offering ASP.NET hosting on the market. However, there are relatively few web hosting providers that offer top-notch ASP.NET hosting.

ASP.NET is the best development language in Windows platform, which is released by Microsoft and widely used to build all types of dynamic Web sites and XML Web services. With this article, we’re going to help you to find the best ASP.NET Hosting solution in Europe based on reliability, features, price, performance and technical support. After we reviewed about 30+ ASP.NET hosting providers in Europe, our Best ASP.NET Hosting Award in Europe goes to HostForLIFE.eu, one of the fastest growing private companies and one of the most reliable hosting providers in Europe.

You may also like...

Popular Posts