1

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?

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
Efie
  • 1,430
  • 2
  • 14
  • 34

1 Answers1

1

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;
    });
}
funatparties
  • 469
  • 4
  • 10
  • Thanks for the link for integration testing. Are you familiar with how to do somethin similar to that for console apps? This is actually just a console app and I'm having trouble finding a `WebApplicationFactory` type class for console apps – Efie Jan 06 '23 at 14:58
  • 1
    Ah that complicates things a lot. The "simplest" solution I can think of is to run full integration tests without mocking anything. I found a good starting point article here https://itsnotbugitsfeature.com/2021/04/30/integration-testing-a-net-core-console-application/. But then you'd have to intercept the http calls your console app is making and fake the responses. This can be achieved by using some proxy server. I can't think of an easier solution without also tampering with your production code. – funatparties Jan 06 '23 at 15:22
  • How much of an undertaking does it sound like from your experience to replicate something like the WebApplicationFactory for my console app? For context we have a few dozen small console apps with a custom ConsoleAppHost and ConsoleAppHostBuilder class. Would it be worth it to do that to make integration testing easier for these kinds of apps or would you see that being a huge mess? – Efie Jan 06 '23 at 15:36
  • 1
    To replicate it fully with all features would be an extremely big effort, but to fake some services like IHttpClientFactory could be doable. Still, it's probably much cleaner and easier to create proper integration tests with some http calls interceptor. You wouldn't need to write it from scratch, there's some good starting points here. https://stackoverflow.com/questions/40129074/c-sharp-intercept-http-request – funatparties Jan 06 '23 at 16:06