top of page

How to use and Unit test HttpClient in Asp.net Core

HttpClient is an important component in ASP.NET Core that enables you to send HTTP requests to remote servers and receive HTTP responses in your application. It provides a simple and efficient way to make network requests and handle responses from external resources, such as RESTful web services, web APIs, and web applications. In this article, we'll cover how to use HttpClient in an ASP.NET Core application and how to write unit tests to ensure that the code works as intended.


What is HttpClient?

HttpClient is a class in ASP.NET Core that provides a way to send HTTP requests to remote servers and receive HTTP responses in your application. It's part of the System.Net.Http namespace and is designed to be lightweight, efficient, and easy to use.


HttpClient is built on top of the underlying HTTP stack provided by the .NET framework and is optimized for performance and scalability. It supports both synchronous and asynchronous operations, making it easy to work with in both web applications and desktop applications.


HttpClient provides a simple and intuitive API for sending HTTP requests and handling responses. You can use it to perform common HTTP operations such as GET, POST, PUT, and DELETE, and you can also customize the behaviour of your requests and responses using options such as headers, timeouts, and content types.


Some of the key benefits of using HttpClient in ASP.NET Core include:

  1. Supports multiple protocols: HttpClient supports several HTTP protocols, including HTTP/1.1, HTTP/2, and HTTP/3, allowing you to communicate with a wide range of remote resources.

  2. Asynchronous: HttpClient is designed to be asynchronous, which means that it can handle multiple requests simultaneously without blocking the main thread of your application. This helps to improve performance and scalability.

  3. Configurable: HttpClient provides a wide range of configuration options, including timeouts, message handlers, and authentication mechanisms, which allow you to customize the behaviour of your HTTP requests and responses.

  4. Extensible: HttpClient is extensible, which means that you can use it to implement custom message handlers and other components that enhance its functionality and integrate it with other parts of your application.

  5. Testable: HttpClient can be easily mocked and tested using unit testing frameworks, allowing you to test the behaviour of your HTTP requests and responses in a controlled environment.


Using HttpClient in ASP.NET Core

Using HttpClient in ASP.NET Core is straightforward. First, we need to create an instance of HttpClient in the ConfigureServices method of our Startup class:

services.AddHttpClient();

This code registers an instance of HttpClient with the DI container. We can now inject this instance into our controllers or services using constructor injection:

public class MyController : ControllerBase
{
    private readonly HttpClient _httpClient;

    public MyController(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    // ...
}

Now, we can use _httpClient to send HTTP requests to external APIs. For example, to send a GET request to an API endpoint and retrieve its response, we can use the GetAsync method:

public async Task<IActionResult> Index()
{
    var response = await _httpClient.GetAsync("https://api.example.com/data");

    if (response.IsSuccessStatusCode)
    {
        var data = await response.Content.ReadAsStringAsync();
        // ...
    }
    else
    {
        // Handle error
    }
}

We can also send POST requests, PUT requests, and other HTTP methods using the corresponding methods of the HttpClient class.


Unit Testing HttpClient in ASP.NET Core

When testing code that uses HttpClient, we want to ensure that our tests are reliable and deterministic. We don't want our tests to actually send HTTP requests to external APIs, as this can introduce flakiness and slow down our test suite. Instead, we can use a technique called "mocking" to simulate the behaviour of the external API and return pre-defined responses.


Mocking HttpClient using Moq

To mock HttpClient, we can use a mocking framework such as Moq. Moq allows us to create "mock" instances of classes or interfaces and define their behaviour using fluent syntax.

First, we need to install the Moq package using NuGet:

dotnet add package Moq

Next, we can create a mock instance of HttpClient in our test method:

var mockHttp = new Mock<HttpClient>();

Now, we can define the behaviour of this mock instance using the Setup method:

mockHttp.Setup(m => m.GetAsync("https://api.example.com/data"))
    .ReturnsAsync(new HttpResponseMessage
    {
        StatusCode = HttpStatusCode.OK,
        Content = new StringContent("[1, 2, 3]")
    });

This code tells the mock instance to return an HTTP response with a 200 OK status code and a JSON payload of "[1, 2, 3]" when the GetAsync method is called with the URL "https://api.example.com/data".


Finally, we can inject this mock instance into our controller or service and write tests that use it:

publicclassMyControllerTests 
{     
    privatereadonly HttpClient _httpClient;      
    
    publicMyControllerTests()     
    {         
        var mockHttp = new Mock<HttpClient>();         
        mockHttp.Setup(m => m.GetAsync("https://api.example.com/data"))             
            .ReturnsAsync(new HttpResponseMessage             
            {                 
                StatusCode = HttpStatusCode.OK,                 
                Content = new StringContent("[1, 2, 3]")             
            });          
            
        _httpClient = mockHttp.Object;     
    }      
    
    [Fact]     
    publicasync Task Test_GetData_ReturnsExpectedData()     
    {         
        // Arrange
        var client = new TestServer(new WebHostBuilder().UseStartup<Startup>())             .CreateClient();         
        var request = new HttpRequestMessage(HttpMethod.Get, "/data");          
        
        // Act
        var response = await _httpClient.SendAsync(request);          
        
        // Assert         
        response.EnsureSuccessStatusCode();         
        var content = await response.Content.ReadAsStringAsync();         
        Assert.Equal("[1, 2, 3]", content);     
    } 
}


Here's an example of how to unit test HttpClient in ASP.NET Core using Moq:

using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Testing;
using Moq;
using Xunit;

public class MyControllerTests : IClassFixture<WebApplicationFactory<Startup>>
{
    private readonly HttpClient _httpClient;
    private readonly Mock<HttpMessageHandler> _mockHttpMessageHandler;

    public MyControllerTests(WebApplicationFactory<Startup> factory)
    {
        _mockHttpMessageHandler = new Mock<HttpMessageHandler>();
        _httpClient = factory.CreateClient(new WebApplicationFactoryClientOptions
        {
            AllowAutoRedirect = false,
            BaseAddress = new Uri("http://localhost"),
            Handler = _mockHttpMessageHandler.Object
        });
    }

    [Fact]
    public async Task Get_Data_Returns_Expected_Data()
    {
        // Arrangevar expectedData = "[1, 2, 3]";
        _mockHttpMessageHandler.Protected()
            .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
            .ReturnsAsync(new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.OK,
                Content = new StringContent(expectedData),
            });

        // Actvar response = await _httpClient.GetAsync("/api/data");
        var responseData = await response.Content.ReadAsStringAsync();

        // Assert
        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal(expectedData, responseData);
    }
}

In this example, we're using the Moq mocking framework to create a mock instance of HttpMessageHandler, which HttpClient uses under the hood to make HTTP requests. We then pass this mock instance to the HttpClient constructor when creating an instance of HttpClient.


Next, we're defining the behaviour of the mock instance by setting up a call to its SendAsync method using the Setup method of the mock instance. In this case, we're telling it to return an HTTP response with a 200 OK status code and a JSON payload of "[1, 2, 3]" when it receives a request with any URL and any HTTP method.


Finally, we're using the HttpClient instance to make a GET request to "/api/data" and verify that the response has an HTTP 200 OK status code and contains the expected data.


By using Moq to mock HttpClient, we can write fast and deterministic unit tests that do not depend on external APIs. We can define the behaviour of the mock instance to simulate different scenarios, such as network errors or server-side errors, and ensure that our code handles them correctly.


Conclusion

HttpClient is a powerful class in the .NET framework that enables developers to send HTTP requests and receive HTTP responses from web APIs. In ASP.NET Core, we can use HttpClient to interact with external APIs and write tests for our API endpoints.


By using Moq to mock HttpClient, we can write fast and reliable unit tests that do not depend on external APIs. We can simulate different scenarios and ensure that our code handles them correctly, making our applications more robust and resilient.

0 comments

Comments


bottom of page