Search code examples
c#.net-coredependency-injectionmockingpolly

Mock http client that is set up inside of Program.cs


I have a typed HttpClient that I am injecting in my application using the HttpClientFactory extension methods for services in Program.cs

My client looks something like this with the HttpClient injected via the constructor:

public class MyClient
{
    private readonly HttpClient _httpClient;
    public MyClient(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<string> GetStuffFromApi()
    {
        // method to get content from API
        // return stuff
    }
}

The relevant section in Program.cs looks something like this for example:

services.AddHttpClient<IMyClient, MyClient>(client =>
{
    client.BaseAddress = new Uri("https://somewebsite.com/api");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
}).AddPolicyHandler(MyClientPolicies.GetRetryAsyncPolicy());        

I would like to test the retry policy among other things for this client. I found a great mockhttp library that is helpful for the mock client setup (MockHttp), but I am unsure of exactly what I need to do in order to include the retry policy behavior in my mocked client.

So the test looks something like this using XUnit currently:

public class MyClientTests
{
    [Fact]
    public async Task MyClient_RetriesRequest_OnTransientErrors()
    {
        // Arrange
        var mockHttp = new MockHttpMessageHandler();
        mockHttp.When("*").Respond(HttpStatusCode.RequestTimeout);
        var mockClient = new MyClient(mockHttp.ToHttpClient());
        // Act
        // ... call the method
        // Assert
        // ... assert the request was tried multiple times
    }
}

How do I test my mock http client including the additional configuration from Program.cs like the baseaddress and retry policies?


Solution

  • You cannot test the retry policy if it's setup like that, in a simple unit test. You have 2 choices.

    1. To create full-service integration tests and then get creative with mock services, following this guideline for integration tests from Microsoft: https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-7.0#inject-mock-services.

    2.To use the retry policy directly in your method which you are testing. Something like:

    public async Task<string> GetStuffFromApi()
    {
        var policy = MyClientPolicies.GetRetryAsyncPolicy()
        await policy.ExecuteAsync(async ctx =>
    
            var request = new HttpRequestMessage(HttpMethod.Get, new Uri("https://www.example.com"));
            var response = await _client.SendAsync(request);
            response.EnsureSuccessStatusCode();
    
            return response;
        });
    }