title: Unit Testing Core API Controller Using Custom HttpClient and Polly policy within ConfigureServices
body: <p>I have problems performing unit testing when using <code>Polly</code> and <code>HttpClient</code>.</p>
  
  <p>Specifically, Polly and HttpClient are used for ASP.NET Core Web API Controller following the links below:</p>
  
  <p><a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests" rel="nofollow noreferrer">https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests</a></p>
  
  <p><a href="https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory" rel="nofollow noreferrer">https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory</a>  </p>
  
  <p>The problems (1 and 2) are specified at the bottom. I wonder if this is the correct way to using <code>Polly</code> and <code>HttpClient</code>.</p>
  
  <p><strong>ConfigureServices</strong></p>
  
  <p>Configure Polly policy and sepecify custom HttpClient, <code>CustomHttpClient</code></p>
  
  <pre><code>  public void ConfigureServices(IServiceCollection services)
  {
     services.AddHttpClient();
     services.AddHttpClient&lt;HttpClientService&gt;()                                
                  .AddPolicyHandler((service, request) =&gt;
                      HttpPolicyExtensions.HandleTransientHttpError()
                          .WaitAndRetryAsync(3,
                              retryCount =&gt; TimeSpan.FromSeconds(Math.Pow(2, retryCount)))
                  );
   }
  </code></pre>
  
  <p><strong>CarController</strong> </p>
  
  <p>CarController depends on <code>HttpClientService</code>, which is injected by the framework automatically without explicit registration. </p>
  
  <p>Please note that <code>HttpClientService</code> causes issues with unit test as <code>Moq</code> cannot mock a non virtual method, which is mentioned later on.</p>
  
  <pre><code> [ApiVersion("1")]
      [Route("api/v{version:apiVersion}/[controller]")]
      [ApiController]
      public class CarController : ControllerBase
      {
          private readonly ILog _logger;
          private readonly HttpClientService _httpClientService;
          private readonly IOptions&lt;Config&gt; _config;
  
          public CarController(ILog logger, HttpClientService httpClientService, IOptions&lt;Config&gt; config)
          {
              _logger = logger;
              _httpClientService = httpClientService;
              _config = config;
          }
  
          [HttpPost]
          public async Task&lt;ActionResult&gt; Post()
          {  
  
              using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
              {
                  string body = reader.ReadToEnd();
  
                      var statusCode = await _httpClientService.PostAsync(
                          "url",
                          new Dictionary&lt;string, string&gt;
                          {
                              {"headerID", "Id"}                           
                          },
                          body);
                      return StatusCode((int)statusCode);               
              }
          }
        }
  </code></pre>
  
  <p><strong>HttpClientService</strong> </p>
  
  <p>Simiar to <code>CarController</code>, <code>HttpClientService</code> has an issue with Unit test, because <code>HttpClient</code>'s PostAsync cannot be mocked. <code>HttpClient</code> is injected by the framework automatically without explicit registration. </p>
  
  <pre><code> public class HttpClientService
  {
      private readonly HttpClient _client;
      public HttpClientService(HttpClient client)
      {
          _client = client;
      }
  
      public async Task&lt;HttpStatusCode&gt; PostAsync(string url, Dictionary&lt;string, string&gt; headers, string body)
      {
          using (var content = new StringContent(body, Encoding.UTF8, "application/json"))
          {
              foreach (var keyValue in headers)
              {
                  content.Headers.Add(keyValue.Key, keyValue.Value);
              }
  
              var response = await _client.PostAsync(url, content);
  
              response.EnsureSuccessStatusCode();
              return response.StatusCode;
          }
  
      }
  </code></pre>
  
  <p><strong>Problem 1</strong></p>
  
  <p>Unit Test: <code>Moq</code> cannot mock <code>HttpClientService</code>'s <code>PostAsync</code> method. I CAN change it to virtual, but I wonder if it is the best option.</p>
  
  <pre><code>public class CarControllerTests
      {
          private readonly Mock&lt;ILog&gt; _logMock;
          private readonly Mock&lt;HttpClient&gt; _httpClientMock;
          private readonly Mock&lt;HttpClientService&gt; _httpClientServiceMock;
          private readonly Mock&lt;IOptions&lt;Config&gt;&gt; _optionMock;
          private readonly CarController _sut;
  
  
          public CarControllerTests()  //runs for each test method
          {
              _logMock = new Mock&lt;ILog&gt;();
              _httpClientMock = new Mock&lt;HttpClient&gt;();
              _httpClientServiceMock = new Mock&lt;HttpClientService&gt;(_httpClientMock.Object);
              _optionMock = new Mock&lt;IOptions&lt;Config&gt;&gt;();
              _sut = new CarController(_logMock.Object, _httpClientServiceMock.Object, _optionMock.Object);
          }
  
              [Fact]
                 public void Post_Returns200()
              {
                      //System.NotSupportedException : Invalid setup on a non-virtual (overridable in VB) member
                          _httpClientServiceMock.Setup(hc =&gt; hc.PostAsync(It.IsAny&lt;string&gt;(),
                          It.IsAny&lt;Dictionary&lt;string, string&gt;&gt;(),
                          It.IsAny&lt;string&gt;()))
                      .Returns(Task.FromResult(HttpStatusCode.OK));
                      }
               }
  
  
  }
  </code></pre>
  
  <p><strong>Problem 2</strong></p>
  
  <p>Unit test: similar to <code>HttpClientService</code>,  <code>Moq</code> cannot mock <code>HttpClient</code>'s <code>PostAsync</code> method.</p>
  
  <pre><code>  public class HttpClientServiceTests
  {
          [Fact]
             public void Post_Returns200()
          {
  
              var httpClientMock = new Mock&lt;HttpClient&gt;();
  
              //System.NotSupportedException : Invalid setup on a non-virtual (overridable in VB) member
          httpClientMock.Setup(hc =&gt; hc.PostAsync("", It.IsAny&lt;HttpContent&gt;()))
              .Returns(Task.FromResult(new HttpResponseMessage()));
              }
  
  }
  </code></pre>
  
  <p>ASP.NET Core API 2.2</p>
  
  <p><strong>Update</strong></p>
  
  <p>Corrected a typo of CustomHttpClient to HttpClientService</p>
  
  <p><strong>Update 2</strong></p>
  
  <p><a href="https://stackoverflow.com/questions/44715602/mock-httpclient-using-moq/44716910#44716910">Solution</a> to problem 2</p>