1

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?

3
  • 2
    You should look in to IHttpClientFactory and typed/named HttpClient injection. Commented Nov 13, 2020 at 22:35
  • 1
    1) Create a test-only overload where you can pass in a custom handler. I've used this approach with great success for years. 2) Abstract the class to an HttpClient and inject that instead. In theory your abstractions should be designed to interfaces and you can hide the fact they even use HTTP. Commented Nov 13, 2020 at 23:26
  • I went with public MyClass(HttpClientHandler httpClientHandler = null) and then called it with a mock: var mockHttpMessageHandler = new Mock<HttpClientHandler>();. It does the job, I'm just not sure, how "clean" or "best practice" it is. Commented Nov 15, 2020 at 16:00

2 Answers 2

1

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);
Sign up to request clarification or add additional context in comments.

1 Comment

This is the same approach that @Andy suggested. I'll definitely have a look into this, when I have more time as this seems more "clean".
1

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.

1 Comment

Well I am testing the underlying Service Class to the Controller. Like fetching and processing data from another page. The result is then given to the Controller. The controller itself is tested against the mocked interface of the Service Layer. The Service Class should be tested in my opinion and to do that I need the HttpClient-mock

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.