Search code examples
c#polly

Polly policy to throw an exception when Execute() is called


I am using a slightly dated version of Polly - 5.9 in one of my projects.

For a test case, I am trying to create a policy that will always throw an exception when Execute() is called on it. This policy will be injected into the actual code at test time and the expectation is for it to fail.

I could do something like:

Policy somePolicy = Policy.Handle<Exception>().Retry();
somePolicy.Execute((cToken) => { throw new Exception(); }, new Context("A context"), cancellationToken); 

However, I do not have access of or control over the first parameter of Execute(), i.e., the (cToken) => { throw new Exception(); } part.

I have also tried a workaround using HandleResult() as follows:

Policy<bool> somePolicy = Policy.HandleResult<bool>((o) => { throw new Exception(); }).Retry();

This works, however, the Policy<bool> makes it cumbersome to integrate with the rest of the code which uses just Policy.

The policy itself does not matter, as long as it throws an exception on any invocation of Execute(). Is there a clean way of achieving this?

PS: Upgrading Polly isn't an option at the moment.


Solution

  • Two options:

    1 Use Simmy

    Simmy is a project providing Polly policies for injecting faults.

    For instance, you can define:

    var faultPolicy = MonkeyPolicy.InjectFault(new FooException());
    

    (and many other more powerful variants).

    However, this is only compatible with Polly v7+.

    2 Use policy interfaces and mock policies

    Polly policies all fulfil execution interfaces. Depending on the policy:

    • ISyncPolicy
    • ISyncPolicy<TResult>
    • IAsyncPolicy
    • IAsyncPolicy<TResult>

    These interfaces define the .Execute/Async() overloads available on the policy.

    With these, you can use standard dependency-injection and mocking techniques to construct a test:

    • In your production code, declare and consume policies by the execution interface type.
    • Make sure the ISyncPolicy or similar (or a PolicyRegistry) is injected into the system-under-test, not created within it, so that tests can substitute a mock.
    • In the unit-test, instead pass in a Mock<ISyncPolicy>. You can then use any mocking tool like Moq to mock the .Execute() call through the policy to throw an exception.

    For example:

    ISyncPolicy mockPolicy = new Mock<ISyncPolicy>();
    mockPolicy.Setup(p => p.Execute(It.IsAny<Func<Bar>>())
        .Throws(new FooException());
    

    This and more is covered in more detail on the Polly wiki on unit-testing, with code examples.