Unit Testing a Method That Uses HttpClient
Full source code available here.
In this post I’m going to show you how to test an action method of controller that uses a HttpClient
. When performing this test you want to isolate just the code of the action method for testing, you want to remove the dependency on the HttpClient
. I hoped it would be simple, that there would be an IHttpClient
, but there is not.
Instead I mocked the HttpMessageHandler
, then pass it to the constructor of the HttpClient
. The HttpMessageHandler
is set to return a list of numbers in response to any request.
The constructor of the controller takes the HttpClient
as a parameter, usually passed by dependency injection.
1public class ValuesController : Controller
2{
3 readonly IAsyncPolicy<HttpResponseMessage> _httpRetryPolicy;
4 private readonly HttpClient _httpClient;
5
6 public ValuesController(HttpClient httpClient)
7 {
8 _httpClient = httpClient;
9 }
10 //snip..
In the test class I mock the HttpMessageHandler
, set its SendAsync
method to return OK and a list of numbers in response to any request. I then pass the mocked HttpMessageHandler
to the constructor of the HttpClient
.
Now the HttpClient
will return the list of numbers I expect and I my test just tests the code of the action method.
The rest of the test is written as normal.
1[Fact]
2public async Task GetTest()
3{
4 //Arrange
5 string numberJson= JsonConvert.SerializeObject(new List<int>() { 1, 2, 3, 4, 5 });
6
7 var httpMessageHandler = new Mock<HttpMessageHandler>();
8 httpMessageHandler.Protected()
9 .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(),
10 ItExpr.IsAny<CancellationToken>())
11 .Returns(Task.FromResult(new HttpResponseMessage
12 {
13 StatusCode = HttpStatusCode.OK,
14 Content = new StringContent(numberJson, Encoding.UTF8, "application/json"),
15 }));
16
17 HttpClient httpClient = new HttpClient(httpMessageHandler.Object);
18 httpClient.BaseAddress = new Uri(@"http://localhost:63781/v1/");
19 httpClient.DefaultRequestHeaders.Accept.Clear();
20 httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
21
22 ValuesController controller = new ValuesController(httpClient);
23
24 //Act
25 IActionResult result = await controller.Get();
26
27 //Assert
28 OkObjectResult resultObject = result as OkObjectResult;
29 Assert.NotNull(resultObject);
30
31 List<int> numbers = resultObject.Value as List<int>;
32 Assert.Equal(5, numbers.Count);
33}
Full source code available here.