Testing Your Code When Using Polly

Full source code here.

When developing an application with Polly you will also probably want to write some unit tests.

Here are the scenarios I test for –

1. How my code behaves when the policy throws an exception, such as TimeoutRejectionException, BulkheadRejectedException or BrokenCircuitException.
2. How my code behaves when a policy becomes active and changes the outcome of a call, such as when an unreliable request works because Polly performs a retry.
3. What my code should do if there was no policy in place.

I have a few classes to demonstrate these scenarios, BusinessLogic.cs and OtherBusinessLogic.cs are the classes under test. ErrorProneCode.cs is the unreliable class that I will mock and pass mocked policies into.

For the first case I use Moq to mock the error prone code so it returns an incorrect value.

[Fact]
public void Should_Return_999_When_TimeoutRejectedException_Thrown()
{
    //Arrange 
    Mock<IErrorProneCode> mockedErrorProneCode = new Mock<IErrorProneCode>();
    mockedErrorProneCode.Setup(e => e.GetSomeNumber()).Returns(0);

    Mock<ISyncPolicy> mockedPolicy = new Mock<ISyncPolicy>();
    mockedPolicy.Setup(p => p.Execute(It.IsAny<Func<int>>())).Throws(new TimeoutRejectedException("Mocked Timeout Exception"));

    IBusinessLogic businessLogic = new BusinessLogic(mockedPolicy.Object, mockedErrorProneCode.Object);

    //Act
    // if there is a TimeoutRejectedException in this CallSomeSlowBadCode it will return 999
    int num = businessLogic.CallSomeSlowBadCode();

    //Assert
    Assert.Equal(999, num);
}

In the next case I verify that the application has correctly used the retry policy method. I use a seeded random number generator that produces an known sequence to return values from the ErrorProneCode class.

  
[Fact]
public void Should_Return_Odd_When_Retry()
{
    //Arrange 
    Mock<IErrorProneCode> mockedErrorProneCode = new Mock<IErrorProneCode>();

    Random rnd = new Random(1); // rnd.Next(10) retruns 2, 1, 4 

    mockedErrorProneCode.Setup(e => e.GetSomeNumber()).Returns(() => rnd.Next(10));

    ISyncPolicy<int> policy = Policy.HandleResult<int>(i => i %2 !=1) // retry if the number is not odd.
        .Retry(1);
    OtherBusinessLogic otherBusinessLogic = new OtherBusinessLogic(policy, mockedErrorProneCode.Object);

    //Act
    int num = otherBusinessLogic.CallSomeCodeThatNeedsToBeRetried();

    //Assert
    Assert.Equal(1, num % 2);
}

Finally, I want to verify that my code will work if no Polly policy is in use. To do this, I pass in a NoOp policy.

[Fact]
public void Should_Return_Even_With_NoOp()
{
    //Arrange 
    Mock<IErrorProneCode> mockedErrorProneCode = new Mock<IErrorProneCode>();

    Random rnd = new Random(1); // rnd.Next(10) retruns 2, 1, 4 

    mockedErrorProneCode.Setup(e => e.GetSomeNumber()).Returns(() => rnd.Next(10));

    ISyncPolicy<int> policy = Policy.NoOp<int>();
    OtherBusinessLogic otherBusinessLogic = new OtherBusinessLogic(policy, mockedErrorProneCode.Object);

    //Act
    int num = otherBusinessLogic.CallSomeCodeThatNeedsToBeRetried();

    //Assert
    Assert.Equal(0, num % 2); //even number
}

Full source code here.

Using the HttpClientInterception to Test Methods That Use a HttpClient

Full source code available here.

In my previous post I showed a way of testing a controller that uses a HttpClient.

I had to mock the HttpMessageHandler pass that to the HttpClient and set a bunch of properties. It works well, but is a bit long winded.

I received a comment from a reader who suggested that I try the JustEat.HttpClientInterception library. It allows you to setup responses to specified requests, and pass these to a HttpClient. Then the HttpClient is passed to the controller.

Here is how the test method looks –

[Fact]
public async Task GetTest()
{
    //Arrange
    List<int> myList = new List<int>() {1, 2, 3, 4, 5};
    
    // setup the interceptor
    HttpRequestInterceptionBuilder builder = new HttpRequestInterceptionBuilder()
        .ForHost("localhost.something.com")
        .ForPath("/v1/numbers")
        .WithJsonContent(myList);
    
    // create the HttpClient from the builder
    // and setup the HttpClientBaseAddress
    HttpClient client = new HttpClientInterceptorOptions()
        .Register(builder).CreateHttpClient("http://localhost.something.com/v1/");

    ValuesController controller = new ValuesController(client);

    //Act
    IActionResult result = await controller.Get();

    //Assert
    OkObjectResult resultObject = result as OkObjectResult;
    Assert.NotNull(resultObject);

    List<int> numbers = resultObject.Value as List<int>;
    Assert.Equal(5, numbers.Count);
}

Briefly, here is the constructor of the values controller. It takes the HttpClient as a parameter, usually passed by dependency injection.

public class ValuesController : Controller
{
    readonly IAsyncPolicy<HttpResponseMessage> _httpRetryPolicy;
    private readonly HttpClient _httpClient;

    public ValuesController(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }
	//snip..

Full source code available here.

Customizing a specific string inside a class using AutoFixture

Full source code.

I’ve been using AutoFixture for a while with my unit tests. It creates objects with prefilled data, saving me the hassle of manually constructing them.

Basic usage

If you want a string from AutoFixture do something like –

string myString = fixture.Create();

//"c2eefff9-9cc2-4358-aee1-2d27b0476e41"

If you want to prefix the string do this –

string myPrefixedString = fixture.Create("Prefix");

//"Prefix191dd4bc-f3ed-4d19-ac36-f3c84c958155"

If you want something that looks like an email address –

string emailAddress = fixture.Create().Address;

//"9ed7e16b-f6df-42d6-8812-d7ea6580f300@example.org"

Where it starts to get a bit tricky is if you have a class like this –

public class Account
{
	public Guid AccountId { get; set; }
	public string Firstname { get; set; }
	public string Lastname { get; set; }
	public IEnumerable<string> EmailAddresses { get; set; }
}

Because I am using a string to represent an email address AutoFixture will give me a string, not an email address.

Here are two solutions.

Solution 1

fixture.Customize<Account>(c => c.With(a => a.EmailAddresses, fixture.CreateMany<MailAddress>().Select(ma => ma.Address.ToString())));

This produces emails that look like –

"f45a37ae-6d2c-42a5-92ac-832e6ea2d028@example.net"
"72625222-e7af-4c29-96ed-4219efc1a859@example.net"
"54a39694-fd7a-458c-8739-0667ec9fa2d7@example.net"

Solution 2


If I want to generate email address that look a little more like real world address I have to create a SpecimenBuilder.

    public class EmailAddressesStringSpecimenBuilder : ISpecimenBuilder
    {
        public object Create(object request, ISpecimenContext context)
        {
            var propertyInfo = request as PropertyInfo;

            if (propertyInfo != null)
            {
                if (propertyInfo.Name == "EmailAddresses" && propertyInfo.PropertyType == typeof (IEnumerable<string>))
                {
					// of course you can customize how the mail addresses are created, you can even use a fixture to create strings 🙂 
                    IEnumerable<string> emailAddresses = new List<string>() {"user1@acme.com", "user2@unknown.com", "user3@nothing.com"};
                    return emailAddresses;
                }
            }
            return new NoSpecimen();
        }
    }

How to use the customizations

            Fixture fixture = new Fixture();

			fixture.Customizations.Add(new EmailAddressesStringSpecimenBuilder());
            // use one of the two customizations here, but not both
			// fixture.Customize<Account>(c => c.With(a => a.EmailAddresses, fixture.CreateMany<MailAddress>().Select(ma => ma.Address.ToString())));

            var account1 = fixture.Create<Account>();
            var account2 = fixture.Create<Account>();

Full source code.