Skip to content

A Simple Approach to Mock HttpClient Calls in C#

Posted in Coding

The recommended way to do HTTP calls using C# is to use HttpClient. This class is disposable, meaning that it should be used inside a using statement. Here is a simple example:

public class MyClass
{
    public MyClass()
    {
        
    }

    public void MyMethod()
    {
        using (var httpClient = new HttpClient());
        {
            HttpResponseMessage response = httpClient.GetAsync("https://ahost.com/").Result;
        }
    }
}

This ensures that the HttpClient instance is properly disposed by the garbage collector once we are done with it.

However, a problem arises when the time comes to unit test MyMethod. With the current implementation, it is impossible to mock the HTTP request. This means that the unit test would end up doing a real HTTP call, which is less than ideal.

The usual approach when it comes to mocking is to inject the dependency, instead of creating it inside the class. However, HttpClient is almost impossible to mock out of the box. This is because it does not implement any interfaces, nor does it have virtual methods. One way to circumvent this problem is to create a wrapper class around HttpClient. That wrapper would parrot back the HttpClient methods that need to be mocked, where the wrapper’s methods would be virtual. Then, you inject the wrapper into MyClass.

This approach has a few drawbacks. First, you need to create and maintain a wrapper, which in the end is unnecessary additional code. Second, since you inject the wrapper, it will probably become an internal attribute of MyClass. By doing so, you need to make sure that you properly dispose the HttpClient present in the wrapper.

A simpler approach does not involve a wrapper at all and it allows us to keep the using statement above. The trick is, instead of trying to inject a HttpClient in MyClass, we inject a HttpClientHandler, and pass the handler to the HttpClient constructor. When it comes time to unit test MyClass, we inject a FakeHttpClientHandler. This fake handler extends HttpClientHandler and overrides the SendAsync method. By using this fake handler, it is possible to mock HTTP responses, capture the request messages for assertions, etc. Here is a complete example.

First, we inject HttpClientHandler as a dependency to MyClass.

public class MyClass
{
    private HttpClientHandler _handler;

    public MyClass(HttpClientHandler handler)
    {
        _handler = handler;
    }

    public void MyMethod()
    {
        using (var httpClient = new HttpClient(_handler, false)); // false means that the handler won't be disposed during the HttpClient's disposal
        {
            HttpResponseMessage response = httpClient.GetAsync("https://ahost.com/").Result;
        }   
    }
}

One important note. If you intend to re-use the handler, like it is the case in this example, make sure to specify that the handler should not be disposed during the disposal of the HttpClient.

Now, in the test project, we create the FakeHttpClientHandler class. It looks like this:

public class FakeHttpClientHandler : HttpClientHandler
{
    public virtual HttpResponseMessage Send(HttpRequestMessage request)
    {
        throw new System.NotImplementedException("Meant for mocking purposes.");
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return Task.FromResult(Send(request));
    }
}

By overriding the SendAsync method as above, any HTTP calls that go through the HttpClient can be faked by mocking the Send method above.

Here is a simple code sample that shows how it is then possible to mock HTTP calls using the FakeHttpClientHandler to unit test MyClass. The test below uses NUnit and moq.

[TestFixture]
class MyClassTest
{
    private MyClass _myClass;

    private Mock<FakeHttpClientHandler> _handler;

    [SetUp]
    public void SetUp()
    {
        _handler = new Mock<FakeHttpClientHandler>() { CallBase = true };

        _myClass = new MyClass(_handler.Object);
    }

    [Test]
    public void GivenASituation_WhenDoingSomething_ThenThisHappens()
    {
        // Given
        _handler.Setup(h => h.Send(It.IsAny<HttpRequestMessage>())).Returns(new HttpResponseMessage()); // Insert the response you want

        // When
        _myClass.MyMethod();

        // Then
        // Assert something
    }
}

One last important detail. It is mandatory to set CallBase = true when creating the mocked FakeHttpClientHandler. This is because we want SendAsync to be called during our tests. By doing so, our mocked method (Send) will be executed. If the CallBase attribute is not set, the moq framework will return a default value for the SendAsync method.

That’s it! If you have another alternative regarding mocking HttpClient calls, please share it in the comments!

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *