user3079834
user3079834

Reputation: 2214

ASP.NET Core mock HttpClient with custom HttpClientHandler

I have trouble mocking with Moq. Normally having a HttpClient I would mock it by injecting the HttpClient in the base class like this:

public class MyClass
{
    private readonly HttpClient httpClient;

    public MyClass(HttpClient httpClient)
    {
        this.httpClient = httpClient;
    }
}

But now I have different functions in my class MyClass that need a custom HttpClientHandler like this:

HttpClientHandler httpClientHandler = new HttpClientHandler();
...
using var client = new HttpClient(httpClientHandler);

If I'd simply inject a HttpClient in MyClassTest with var service = new MyClass(httpMock.Object);, then the httpClient would be overwritten.

What would be the right way to test my functions and not making a real HTTP-call?

Upvotes: 1

Views: 3576

Answers (2)

belgaard
belgaard

Reputation: 11

What would be the right way to test my functions and not making a real HTTP-call?

Maybe not what you are looking for, but I suggest you consider Andrew Lock's wisdom - don't unit-test API/MVC controllers in ASP.NET Core.

For .NET Core (and .NET 5) you should avoid mocking HttpClient if you are testing a controller class.

If a controller class is not your SUT, I would wrap the HttpClient in a facade interface and mock that.

Upvotes: 1

Peter Csala
Peter Csala

Reputation: 22849

I suppose you are using typed client approach of the IHttpClientFactory. That's why your MyClass ctor receives an HttpClient instance.

If you need to mock that HttpClient then I suggest you to follow Hamid Mosalla's advice.

In short there is a helper class, which makes HttpMessageHandler's SendAsync mockable (without the need to use the Moq.Protected).

public class FakeHandler: HttpMessageHandler
{
    public virtual HttpResponseMessage Send(HttpRequestMessage request)
    {
        throw new NotImplementedException();
    }

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

You can use this helper class like this to mock any HttpClient call:

var httpResponse = new HttpResponseMessage
{
    Content = new StringContent(JsonConvert.SerializeObject(responseObject))
};

var mockHandler = new Mock<FakeHandler> { CallBase = true };
mockHandler
    .Setup(handler => handler.Send(It.IsAny<HttpRequestMessage>()))
    .Returns(httpResponse);

var mockHttpClient = new HttpClient(mockHandler.Object);
var SUT = new MyClass(mockHttpClient);

Upvotes: 1

Related Questions