Mocking Httpclient Using XUnit In .Net Core

Introduction

 
This article explains how to mock the HttpClient using XUnit. Yes, we already have few ways to mock httpclient by writing a wrapper for HttpClient. But there is a problem for not covering test cases for HttpClient class, since we know there isn't an interface inherited with HttpClient. To handle this case, we introduced HttpClient property in the interface. Using this interface property we can achieve whatever we want around httpclient mocking.
 
Problem Statement
 
As I already mentioned, HttpClient does not inherit from any interface, so you will have to write your own. A few of them suggest a decorator-like pattern.
 
So, here we are mocking only wrapper class and not httpclient. So how can we mock httpclient as well? Let's see it in action, I am using Visual Studio 2019, .Net Core 2.0, and XUnit.
 
Step 1
 
To demonstrate httpclient mocking using Xunit, I am creating a simple web API application and adding a new test(XUnit) project.
 
Mocking Httpclient Using XUnit In .Net Core
 
Step 2
 
Let's introduce IHttpClientHelper interface to mock httpclient. Here you can see HttpClient property as well, which is used to hold the mocked HttpMessageHandler object.
 
Mocking Httpclient Using XUnit In .Net Core
 
The implementation class for IHttpClientHelper looks like below:
  1. using System;  
  2. using System.Net.Http;  
  3. using System.Net.Http.Headers;  
  4. using System.Threading.Tasks;  
  5.   
  6. namespace Demo.Services  
  7. {  
  8.   
  9.     public class HttpClientHelper : IHttpClientHelper  
  10.     {  
  11.         public HttpClient HttpClient { getset; }  
  12.   
  13.         public async Task<TResult> GetAsync<TResult>(string requestUri)  
  14.         {  
  15.             TResult objResult = default(TResult);  
  16.   
  17.             using (var client = this.GetHttpClient())  
  18.             {  
  19.                 using (var response = await client.GetAsync(requestUri))  
  20.                 {  
  21.                     if (TryParse<TResult>(response, out objResult))  
  22.                     {  
  23.                         return objResult;  
  24.                     }  
  25.   
  26.                     using (HttpContent content = response.Content)  
  27.                     {  
  28.                         throw new HttpRequestException(response.Content.ReadAsStringAsync().Result);  
  29.                     }  
  30.                 }  
  31.             }  
  32.         }  
  33.         private HttpClient GetHttpClient()  
  34.         {  
  35.             if (HttpClient == null)//While mocking we set httpclient object to bypass actual result.  
  36.             {  
  37.                 var _httpClient = new HttpClient();  
  38.                 _httpClient.DefaultRequestHeaders.Accept.Clear();  
  39.                 _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));  
  40.                 return _httpClient;  
  41.             }  
  42.             return HttpClient;  
  43.         }  
  44.   
  45.         private bool TryParse<TResult>(HttpResponseMessage response, out TResult t)  
  46.         {  
  47.             if (typeof(TResult).IsAssignableFrom(typeof(HttpResponseMessage)))  
  48.             {  
  49.                 t = (TResult)Convert.ChangeType(response, typeof(TResult));  
  50.                 return true;  
  51.             }  
  52.   
  53.             if (response.IsSuccessStatusCode)  
  54.             {  
  55.                 t = response.Content.ReadAsAsync<TResult>().Result;  
  56.                 return true;  
  57.             }  
  58.   
  59.             t = default(TResult);  
  60.             return false;  
  61.         }  
  62.     }  
  63. }  
Step 3
 
Alright, we have implemented wrapper class for HttpClient. Now let's move into Test project and write test cases for above GetAsync() method. We will see how to mock the HttpClient using the interface property.
  1. using AutoFixture;    
  2. using Demo.Models;    
  3. using Demo.Services;    
  4. using Moq;    
  5. using Moq.Protected;    
  6. using System;    
  7. using System.Collections.Generic;    
  8. using System.Net;    
  9. using System.Net.Http;    
  10. using System.Net.Http.Headers;    
  11. using System.Threading;    
  12. using System.Threading.Tasks;    
  13. using Xunit;    
  14.     
  15. namespace Demo.Test    
  16. {    
  17.     public class HttpClientHelperTest    
  18.     {    
  19.         protected HttpClientHelper HttpClientHelperUnderTest { get; }    
  20.         public HttpClientHelperTest()    
  21.         {    
  22.             HttpClientHelperUnderTest = new HttpClientHelper();    
  23.         }    
  24.     
  25.         /// <summary>    
  26.         /// GetAsync() test cases are resides here  
  27.         /// </summary>    
  28.         public class GetAsyncHttpHelper : HttpClientHelperTest    
  29.         {    
  30.             [Fact]    
  31.             public async Task When_GetAsync_Returns_Success_Result()    
  32.             {    
  33.                 //Arrange;    
  34.                 var result = new List<Weather>()  {  //Weather is an custom class  
  35.                      new Weather() { Description="Test",Temp_max=1.1, Temp_min=1.1 }    
  36.                 };    
  37.                 var httpMessageHandler = new Mock<HttpMessageHandler>();    
  38.                 var fixture = new Fixture();    
  39.     
  40.                 // Setup Protected method on HttpMessageHandler mock.    
  41.                 httpMessageHandler.Protected()    
  42.                     .Setup<Task<HttpResponseMessage>>(    
  43.                         "SendAsync",    
  44.                         ItExpr.IsAny<HttpRequestMessage>(),    
  45.                         ItExpr.IsAny<CancellationToken>()    
  46.                     )    
  47.                     .ReturnsAsync((HttpRequestMessage request, CancellationToken token) =>    
  48.                     {    
  49.                         HttpResponseMessage response = new HttpResponseMessage();    
  50.                         response.StatusCode = System.Net.HttpStatusCode.OK;//Setting statuscode    
  51.                         response.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(result)); // configure your response here    
  52.                         response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); //Setting media type for the response    
  53.                         return response;    
  54.                     });    
  55.     
  56.                 var httpClient = new HttpClient(httpMessageHandler.Object);    
  57.                 httpClient.BaseAddress = fixture.Create<Uri>();    
  58.     
  59.                 HttpClientHelperUnderTest.HttpClient = httpClient; //Mocking setting Httphandler object to interface property.    
  60.     
  61.                 //Act    
  62.                 var weatherResult = await HttpClientHelperUnderTest.GetAsync<List<Weather>>(string.Empty); //Return list of weather information for specific GET Uri.   
  63.     
  64.                 // Assert    
  65.                 Assert.NotNull(weatherResult);    
  66.             }    
  67.         }    
  68.     }    
  69. }    
Here you can see mocking the HttpMessageHandler and assigning it to a HttpClient constructor. 
 
SendAsync() is default implementation for all the HttpClient actions.
  1. public class HttpClient : HttpMessageInvoker  
HttpMessageInvoker class looks like below.
 
Mocking Httpclient Using XUnit In .Net Core
 
Step 4
 
Let's quickly check the test case results:
 
Mocking Httpclient Using XUnit In .Net Core
 
Note
I have attached a sample project with this article. If you want more explanation or a live example, please download the project and refer to that.  
 
Reference 
https://dejanstojanovic.net/aspnet/2020/march/mocking-httpclient-in-unit-tests-with-moq-and-xunit/ 
 
I hope this was helpful to you. Enjoy ;)