Search code examples
c#unit-testingpolly

How do I mock PolicyResult to contain a value for FinalException?


I have created an abstract class that implements Polly that I want to write unit tests for. In one of my tests I want to test how my method handles certain values of PolicyResult.FinalException. Because the returned PolicyResult is null I get a NullReferenceException when evaluating result.FinalException How do I mock the returned result?

What I have so far:

public class AbstractRestClientTest
{
    private AbstractRestClient _sut;

    private Mock<IRestRequestFactory> _requestFactoryMock;

    private Mock<IRestClientFactory> _restClientfactoryMock;
    private Mock<IPollyPolicyFactory> _policyFactoryMock;
    private Mock<IAsyncPolicy> _policyMock;

    private const string DUMMY_URL = "http://dosomething.com/getmesomething";

    [SetUp]
    public void SetUp()
    {
        _requestFactoryMock = new Mock<IRestRequestFactory>();
        
        _restClientfactoryMock = new Mock<IRestClientFactory>();
        _policyFactoryMock = new Mock<IPollyPolicyFactory>();
        var settings = new MockSettings();

        _policyMock = new Mock<IAsyncPolicy>();
        _policyFactoryMock.Setup(mock => 
            mock.CreateAsyncResiliencePolicy(settings))
            .Returns(_policyMock.Object);

        _sut = new MockRestClient(settings, _restClientfactoryMock.Object, 
            _policyFactoryMock.Object,
            _requestFactoryMock.Object);
    }
}

public class MockRestClient : AbstractRestClient
{
    public MockRestClient(RestSettings settings, IRestClientFactory restClientFactory, IPollyPolicyFactory pollyPolicyFactory,
        IRestRequestFactory requestFactory) : base(settings, restClientFactory, pollyPolicyFactory, requestFactory) {
    }
}

public class MockSettings : RestSettings
{
    public override string Naam => "TestSettings";
}

------------------ EDIT 1 --------------------------------

With Nkosi's comment I got a little bit further but still PolicyResult returned by _policy.ExecuteAndCaptureAsync is null. This leads me to believe that there is something wrong in the way that I mock that method. I changed my test to the following but still it returns `null``:

[Test]
public async Task HandleRequest_IfFinalExceptionNotNull_ThenThrowsException()
{
    var mockResult = new Mock<IRestResponse<int>>();
    PolicyResult<IRestResponse<int>> result = PolicyResult<IRestResponse<int>>.Failure(mockResult.Object, new Context());

    //Is the following mock correctly setup?
    _policyMock.Setup(mock => mock.ExecuteAndCaptureAsync(It.IsAny<Func<Task<IRestResponse<int>>>>()))
            .ReturnsAsync(result);

    var url = new Url(DUMMY_URL);
    Assert.ThrowsAsync<Exception>(() => _sut.GetResult<int>(url));
}

I evaluated the parameters needed for ExecuteAndCapture and changed my setup for this method accordingly, what am I doing wrong?


Solution

  • The issue was I was mocking the wrong version of ExecuteAndCaptureAsync, I needed to mock the method with the following signature:

    `Task<PolicyResult> ExecuteAndCaptureAsync(Func<CancellationToken, Task> action, CancellationToken cancellationToken);`
    

    So after I changes my SetUp accordingly the test succeeded:

    [Test]
    public async Task HandleRequest_IfFinalExceptionNotNull_ThenThrowsException()
    {
        var mockResult = new Mock<IRestResponse<int>>();
        PolicyResult<IRestResponse<int>> result = PolicyResult<IRestResponse<int>>.Failure(mockResult.Object, new Context());
    
        _policyMock.Setup(mock => mock.ExecuteAndCaptureAsync(
            It.IsAny<Func<CancellationToken, Task<IRestResponse<int>>>>(), 
            It.IsAny<CancellationToken>()))
        .ReturnsAsync(result);
    
        var url = new Url(DUMMY_URL);
        Assert.ThrowsAsync<Exception>(() => _sut.GetResultaat(url, new CancellationToken()));
    }