Ron Liao
2 min readMay 21, 2023

Build a resilient .NET service with Polly Retry Policy and Unit Tests

Today more and more cloud native microservices are being deployed, often in Kubernetes with layers of external API calls. Transient errors are inevitable, so building a solid and resilient solution becomes essential.

One of the most popular NuGet Packages is Polly with total downloads of 357.4 and GitHub star close to 12k.

Writing a solid and resilient cloud service requires writing quality unit tests. Good unit tests will give developers confidence and improve code quality. I’ll focus on writing unit tests using testing frameworks and libraries such as Moq, xUnit, and FluentAssertions.

///
/// Method using Polly retry policies to be tested
///
public static IAsyncPolicy<HttpResponseMessage> GetRequestRetryPolicy(int retries = 3, double waitSeconds = 1)
{
return Policy.Handle<HttpRequestException>()
.HandleTransientHttpError() // <- an extension method from Polly
.WaitAndRetryAsync(
retryCount: retries,
sleepDurationProvider: retryCount => TimeSpan.FromSeconds(waitSeconds * retryCount));
}

///
/// Test method to ensure transient request will be retried according
/// to the policy configured
///

[Theory]
[InlineData(RetryCount.None, HttpStatusCode.RequestTimeout)]
[InlineData(RetryCount.First, HttpStatusCode.Ambiguous)]
[InlineData(RetryCount.Second, HttpStatusCode.Conflict)]
[InlineData(RetryCount.Third, HttpStatusCode.MethodNotAllowed)]
[InlineData(RetryCount.Fourth, HttpStatusCode.OK)]
public void GetPollyRetryPolicy_Retries_Transient_Errors(RetryCount retryCount, HttpStatusCode expectedHttpStatusCode)
{
// Arrange
var httpResponseMessage = PollyPolicies.GetRequestRetryPolicy((int)retryCount, 0.01);
var mock = new Mock<IDummyResponse>();

/* Mock http request responses based on InlineData parameter */
mock.SetupSequence(t => t.ShouldRetry())
.Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.RequestTimeout)))
.Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.Ambiguous)))
.Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.Conflict)))
.Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.MethodNotAllowed)))
.Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));

//Act
var result = httpResponseMessage.ExecuteAsync( () => mock.Object.ShouldRetry()).Result;

//Assert
result.StatusCode.Should().Be(expectedHttpStatusCode);
}

In summary, retry policy makes software engineers life easier to write resilient .NET service. Writing highly scalable and reliable microservices can be complex and challenging, with framework like Polly, Moq, and xUnit, developers can find confidence in deploying their services into Kubernetes.

Ron Liao

Ron is lifetime learner and has the thirst for knowledge. He has been in software development industry for decades and like helping other people succeed.