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.

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.

The implementation class for IHttpClientHelper looks like below:
- using System;
- using System.Net.Http;
- using System.Net.Http.Headers;
- using System.Threading.Tasks;
- namespace Demo.Services
- {
- public class HttpClientHelper : IHttpClientHelper
- {
- public HttpClient HttpClient { get; set; }
- public async Task<TResult> GetAsync<TResult>(string requestUri)
- {
- TResult objResult = default(TResult);
- using (var client = this.GetHttpClient())
- {
- using (var response = await client.GetAsync(requestUri))
- {
- if (TryParse<TResult>(response, out objResult))
- {
- return objResult;
- }
- using (HttpContent content = response.Content)
- {
- throw new HttpRequestException(response.Content.ReadAsStringAsync().Result);
- }
- }
- }
- }
- private HttpClient GetHttpClient()
- {
- if (HttpClient == null)//While mocking we set httpclient object to bypass actual result.
- {
- var _httpClient = new HttpClient();
- _httpClient.DefaultRequestHeaders.Accept.Clear();
- _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
- return _httpClient;
- }
- return HttpClient;
- }
- private bool TryParse<TResult>(HttpResponseMessage response, out TResult t)
- {
- if (typeof(TResult).IsAssignableFrom(typeof(HttpResponseMessage)))
- {
- t = (TResult)Convert.ChangeType(response, typeof(TResult));
- return true;
- }
- if (response.IsSuccessStatusCode)
- {
- t = response.Content.ReadAsAsync<TResult>().Result;
- return true;
- }
- t = default(TResult);
- return false;
- }
- }
- }
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.
- using AutoFixture;
- using Demo.Models;
- using Demo.Services;
- using Moq;
- using Moq.Protected;
- using System;
- using System.Collections.Generic;
- using System.Net;
- using System.Net.Http;
- using System.Net.Http.Headers;
- using System.Threading;
- using System.Threading.Tasks;
- using Xunit;
- namespace Demo.Test
- {
- public class HttpClientHelperTest
- {
- protected HttpClientHelper HttpClientHelperUnderTest { get; }
- public HttpClientHelperTest()
- {
- HttpClientHelperUnderTest = new HttpClientHelper();
- }
- /// <summary>
- /// GetAsync() test cases are resides here
- /// </summary>
- public class GetAsyncHttpHelper : HttpClientHelperTest
- {
- [Fact]
- public async Task When_GetAsync_Returns_Success_Result()
- {
- //Arrange;
- var result = new List<Weather>() { //Weather is an custom class
- new Weather() { Description="Test",Temp_max=1.1, Temp_min=1.1 }
- };
- var httpMessageHandler = new Mock<HttpMessageHandler>();
- var fixture = new Fixture();
- // Setup Protected method on HttpMessageHandler mock.
- httpMessageHandler.Protected()
- .Setup<Task<HttpResponseMessage>>(
- "SendAsync",
- ItExpr.IsAny<HttpRequestMessage>(),
- ItExpr.IsAny<CancellationToken>()
- )
- .ReturnsAsync((HttpRequestMessage request, CancellationToken token) =>
- {
- HttpResponseMessage response = new HttpResponseMessage();
- response.StatusCode = System.Net.HttpStatusCode.OK;//Setting statuscode
- response.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(result)); // configure your response here
- response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); //Setting media type for the response
- return response;
- });
- var httpClient = new HttpClient(httpMessageHandler.Object);
- httpClient.BaseAddress = fixture.Create<Uri>();
- HttpClientHelperUnderTest.HttpClient = httpClient; //Mocking setting Httphandler object to interface property.
- //Act
- var weatherResult = await HttpClientHelperUnderTest.GetAsync<List<Weather>>(string.Empty); //Return list of weather information for specific GET Uri.
- // Assert
- Assert.NotNull(weatherResult);
- }
- }
- }
- }
Here you can see mocking the HttpMessageHandler and assigning it to a HttpClient constructor.
SendAsync() is default implementation for all the HttpClient actions.
- public class HttpClient : HttpMessageInvoker
HttpMessageInvoker class looks like below.

Step 4
Let's quickly check the test case results:

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 ;)

Bhavesh Ramburn BSc (hons), LLM, MCIArbPosted Jul 30, 2022, 7:51 PM
Thanks mate I was looking for a solution to this.