0

I am very new to Testing. I am trying to understand how can I unit test since I do not really need to actually trigger these services but probably mock every step.

How can I unit test the following piece of code?

public void myFunction()
{
// I am getting an auth token from a service
// then 

    using (HttpClient httpClient = new HttpClient())
    {
    // do a POST call on another service
    var response = httpClient.PostAsync(url, content);
    }

}
xtc
  • 63
  • 7
  • That code is wrong because you're creating a new instance of `HttpClient`. – ProgrammingLlama Jan 13 '22 at 01:54
  • 2
    See [You're using HttpClient wrong and it is destabilizing your software](https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/) and the follow-up [You're (probably still) using HttpClient wrong and it is destabilizing your software](https://josef.codes/you-are-probably-still-using-httpclient-wrong-and-it-is-destabilizing-your-software/) for more info. – ProgrammingLlama Jan 13 '22 at 01:55
  • that is not the test code. – xtc Jan 13 '22 at 01:55
  • 1
    It not being test code makes it worse. And using `HttpClient` the correct way would allow you to to inject one with a mocked handler, allowing you to unit test it. – ProgrammingLlama Jan 13 '22 at 01:56
  • @Llama any example i can refer to? – xtc Jan 13 '22 at 01:57
  • Perhaps [this answer](https://stackoverflow.com/questions/36425008/mocking-httpclient-in-unit-tests) – ProgrammingLlama Jan 13 '22 at 02:16

2 Answers2

1

Non-overridable members (here: HttpClient.PostAsync) may not be used in setup / verification expressions.

I also tried to mock the HttpClient the same way you did, and I got the same error message.

Non-overridable members (here: HttpClient.PostAsync) may not be used in setup / verification expressions.

I also tried to mock the HttpClient the same way you did, and I got the same error message.

Solution: Instead of mocking the HttpClient, mock the HttpMessageHandler.

Then give the

mockHttpMessageHandler.Object

to your HttpClient, which you then pass to your product code class. This works because HttpClient uses HttpMessageHandler under the hood:

// Arrange
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
mockHttpMessageHandler.Protected()
    .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
    .ReturnsAsync(new HttpResponseMessage { StatusCode = HttpStatusCode.OK });

var client = new HttpClient(mockHttpMessageHandler.Object);
this._iADLS_Operations = new ADLS_Operations(client);

Note: You will also need a

using Moq.Protected;

at the top of your test file.

Then you can call your method that uses PostAsync from your test, and PostAsync will return an HTTP status OK response:

var returnedItem = this._iADLS_Operations.MethodThatUsesPostAsync(/*parameter(s) here*/);

Advantage: Mocking HttpMessageHandler means that you don't need extra classes in your product code or your test code.

Helpful resources:


https://chrissainty.com/unit-testing-with-httpclient/


https://gingter.org/2018/07/26/how-to-mock-httpclient-in-your-net-c-unit-tests/

1

After mock arrangements can be verify with

mockHttpMessageHandler.Protected().Verify("SendAsync", Times.Once(), ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>());
malisasmaz
  • 99
  • 1
  • 7