Full source code available here.
In this post I’m going to show you how 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.
public class ValuesController : Controller { readonly IAsyncPolicy<HttpResponseMessage> _httpRetryPolicy; private readonly HttpClient _httpClient; public ValuesController(HttpClient httpClient) { _httpClient = httpClient; } //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.
[Fact] public async Task GetTest() { //Arrange string numberJson= JsonConvert.SerializeObject(new List<int>() { 1, 2, 3, 4, 5 }); var httpMessageHandler = new Mock<HttpMessageHandler>(); httpMessageHandler.Protected() .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>()) .Returns(Task.FromResult(new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Content = new StringContent(numberJson, Encoding.UTF8, "application/json"), })); HttpClient httpClient = new HttpClient(httpMessageHandler.Object); httpClient.BaseAddress = new Uri(@"http://localhost:63781/v1/"); httpClient.DefaultRequestHeaders.Accept.Clear(); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); ValuesController controller = new ValuesController(httpClient); //Act IActionResult result = await controller.Get(); //Assert OkObjectResult resultObject = result as OkObjectResult; Assert.NotNull(resultObject); List<int> numbers = resultObject.Value as List<int>; Assert.Equal(5, numbers.Count); }
Full source code available here.