Testing Your Code When Using Polly
Full source code here.
Want to learn more about Polly? Check out my Pluralsight course on it.
When developing an application with Polly you will also probably want to write some unit tests.
Here are the scenarios I test for -
- How my code behaves when the policy throws an exception, such as TimeoutRejectionException, BulkheadRejectedException or BrokenCircuitException.
- 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.
- 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.
1[Fact]
2public void Should_Return_999_When_TimeoutRejectedException_Thrown()
3{
4 //Arrange
5 Mock<IErrorProneCode> mockedErrorProneCode = new Mock<IErrorProneCode>();
6 mockedErrorProneCode.Setup(e => e.GetSomeNumber()).Returns(0);
7
8 Mock<ISyncPolicy> mockedPolicy = new Mock<ISyncPolicy>();
9 mockedPolicy.Setup(p => p.Execute(It.IsAny<Func<int>>())).Throws(new TimeoutRejectedException("Mocked Timeout Exception"));
10
11 IBusinessLogic businessLogic = new BusinessLogic(mockedPolicy.Object, mockedErrorProneCode.Object);
12
13 //Act
14 // if there is a TimeoutRejectedException in this CallSomeSlowBadCode it will return 999
15 int num = businessLogic.CallSomeSlowBadCode();
16
17 //Assert
18 Assert.Equal(999, num);
19}
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.
1[Fact]
2public void Should_Return_Odd_When_Retry()
3{
4 //Arrange
5 Mock<IErrorProneCode> mockedErrorProneCode = new Mock<IErrorProneCode>();
6
7 Random rnd = new Random(1); // rnd.Next(10) retruns 2, 1, 4
8
9 mockedErrorProneCode.Setup(e => e.GetSomeNumber()).Returns(() => rnd.Next(10));
10
11 ISyncPolicy<int> policy = Policy.HandleResult<int>(i => i %2 !=1) // retry if the number is not odd.
12 .Retry(1);
13 OtherBusinessLogic otherBusinessLogic = new OtherBusinessLogic(policy, mockedErrorProneCode.Object);
14
15 //Act
16 int num = otherBusinessLogic.CallSomeCodeThatNeedsToBeRetried();
17
18 //Assert
19 Assert.Equal(1, num % 2);
20}
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.
1[Fact]
2public void Should_Return_Even_With_NoOp()
3{
4 //Arrange
5 Mock<IErrorProneCode> mockedErrorProneCode = new Mock<IErrorProneCode>();
6
7 Random rnd = new Random(1); // rnd.Next(10) retruns 2, 1, 4
8
9 mockedErrorProneCode.Setup(e => e.GetSomeNumber()).Returns(() => rnd.Next(10));
10
11 ISyncPolicy<int> policy = Policy.NoOp<int>();
12 OtherBusinessLogic otherBusinessLogic = new OtherBusinessLogic(policy, mockedErrorProneCode.Object);
13
14 //Act
15 int num = otherBusinessLogic.CallSomeCodeThatNeedsToBeRetried();
16
17 //Assert
18 Assert.Equal(0, num % 2); //even number
19}
Full source code here.