During startup I basically add an HttpClient
like this:
services.AddHttpClient<IHttpClient, MyHttpClient>().AddPolicyHandler(GetRetryPolicy());
public IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(message => message.StatusCode == HttpStatusCode.NotFound)
.WaitAndRetryAsync(GetBackOffDelay(options),
onRetry: (result, timespan, retryAttempt, context) =>
{
context.GetLogger()?.LogWarning($"Failure with status code {result.Result.StatusCode}. Retry attempt {retryAttempt}. Retrying in {timespan}.");
}));
}
How can I test that the retry policy works as expected? I've tried writing a test like this:
public async Task MyTest()
{
var policy = GetMockRetryPolicy(); // returns the policy shown above.
var content = HttpStatusCode.InternalServerError;
var services = new ServiceCollection();
services.AddHttpClient<IHttpClient, MyFakeClient>()
.AddPolicyHandler(policy);
var client = (MyFakeClient)services.BuildServiceProvider().GetRequiredService<IHttpClient>();
await client.Post(new Uri("https://someurl.com")), content);
// Some asserts that don't work right now
}
For reference here's the bulk of my Post
method on MyFakeClient
:
if(Enum.TryParse(content.ToString(), out HttpStatusCode statusCode))
{
if(statusCode == HttpStatusCode.InternalServerError)
{
throw new HttpResponseException(new Exception("Internal Server Error"), (int)HttpStatusCode.InternalServerError);
}
}
The MyFakeClient
has a Post
method that checks to see if the content is an HttpStatusCode
and if it's an internal server error throws an HttpResponseException
. At the moment, this creates the correct client and triggers the post fine. It throws the HttpResponseException
but in doing so exits the test rather than using the retry policy.
How can I get it to use the retry policy in the test?
CodePudding user response:
The thing is you can't really unit test this:
- The retry is registered on the top of the
HttpClient
via the DI. When you are unit testing then you are not relying on the DI rather on individual components. So, integration testing might be more suitable for this. I've already detailed how can you do that via WireMock.Net. The basic idea is to create a local http server (mocking the downstream system) with predefined response sequence. - After you have defined the retry policy (with the retry count, time penalties) you can not retrieve them easily. So, from a unit testing perspective it is really hard to make sure that the policy has been defined correctly (like the delay is specified in seconds, not in minutes). I've already created a github issue for that, but unfortunately the development of the new version has been stuck.