[c#] Mocking HttpClient in unit tests

Your interface exposes the concrete HttpClient class, therefore any classes that use this interface are tied to it, this means that it cannot be mocked.

HttpClient does not inherit from any interface so you will have to write your own. I suggest a decorator-like pattern:

public interface IHttpHandler
{
    HttpResponseMessage Get(string url);
    HttpResponseMessage Post(string url, HttpContent content);
    Task<HttpResponseMessage> GetAsync(string url);
    Task<HttpResponseMessage> PostAsync(string url, HttpContent content);
}

And your class will look like this:

public class HttpClientHandler : IHttpHandler
{
    private HttpClient _client = new HttpClient();

    public HttpResponseMessage Get(string url)
    {
        return GetAsync(url).Result;
    }

    public HttpResponseMessage Post(string url, HttpContent content)
    {
        return PostAsync(url, content).Result;
    }

    public async Task<HttpResponseMessage> GetAsync(string url)
    {
        return await _client.GetAsync(url);
    }

    public async Task<HttpResponseMessage> PostAsync(string url, HttpContent content)
    {
        return await _client.PostAsync(url, content);
    }
}

The point in all of this is that HttpClientHandler creates its own HttpClient, you could then of course create multiple classes that implement IHttpHandler in different ways.

The main issue with this approach is that you are effectively writing a class that just calls methods in another class, however you could create a class that inherits from HttpClient (See Nkosi's example, it's a much better approach than mine). Life would be much easier if HttpClient had an interface that you could mock, unfortunately it does not.

This example is not the golden ticket however. IHttpHandler still relies on HttpResponseMessage, which belongs to System.Net.Http namespace, therefore if you do need other implementations other than HttpClient, you will have to perform some kind of mapping to convert their responses into HttpResponseMessage objects. This of course is only a problem if you need to use multiple implementations of IHttpHandler but it doesn't look like you do so it's not the end of the world, but it's something to think about.

Anyway, you can simply mock IHttpHandler without having to worry about the concrete HttpClient class as it has been abstracted away.

I recommend testing the non-async methods, as these still call the asynchronous methods but without the hassle of having to worry about unit testing asynchronous methods, see here

Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to unit-testing

Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0 How to test the type of a thrown exception in Jest Unit Tests not discovered in Visual Studio 2017 Class Not Found: Empty Test Suite in IntelliJ Angular 2 Unit Tests: Cannot find name 'describe' Enzyme - How to access and set <input> value? Mocking HttpClient in unit tests Example of Mockito's argumentCaptor How to write unit testing for Angular / TypeScript for private methods with Jasmine Why is the Visual Studio 2015/2017/2019 Test Runner not discovering my xUnit v2 tests

Examples related to moq

Mocking HttpClient in unit tests Why am I getting an Exception with the message "Invalid setup on a non-virtual (overridable in VB) member..."? How can I tell Moq to return a Task? How to mock static methods in c# using MOQ framework? Moq, SetupGet, Mocking a property Mocking a method to throw an exception (moq), but otherwise act like the mocked object? Verify a method call using Moq Verifying a specific parameter with Moq Mocking Extension Methods with Moq Assigning out/ref parameters in Moq