用于Polly AsyncPolicy的单元测试SleepDurationProvider方法

问题描述

当前解决方

我有一个C#库,其中包含一个拥有多个API并以各种方式利用所有API的主类。每个API都将其HttpClient.SendAsync包装在Polly AsyncPolicy.ExecuteAsync中。通过在主类CreateRetryPolicy调用一个需要两个委托sleepDurationProvideronRetryAsync方法来创建此异步策略:

public class MainClass
{
    private readonly IFirstApi firstApi;
    private readonly ISecondApi secondApi;

    private readonly HttpClient httpClient = new HttpClient();

    public MainClass()
    {
        firstApi = new FirstApi(httpClient,CreateRetryPolicy);
        secondApi = new SecondApi(httpClient,CreateRetryPolicy);
    }

    // Main class code that uses APIs

    public static AsyncPolicy<HttpResponseMessage> CreateRetryPolicy(
        Func<int,TimeSpan> sleepDurationProvider,Func<DelegateResult<HttpResponseMessage>,TimeSpan,Context,Task> onRetryAsync
        )
    {
        return Policy.HandleResult<HttpResponseMessage>(
            r => !r.IsSuccessstatusCode)
            .Or<TaskCanceledException>()
            .WaitAndRetryAsync(
                5,sleepDurationProvider: sleepDurationProvider,onRetryAsync: onRetryAsync
                );
    }
}

如您所见,每个API在构造时都被赋予CreateRetryPolicy方法,该方法存储在名为retryPolicy的委托中,并允许它们通过同时传递sleepDurationProvider来创建个性化策略。和onRetryAsync名代表。这两个方法BaseApi抽象类(由所有API类继承)实现为受保护的方法SleepDurationRetryAction

public abstract class BaseApi
{
    // Other members needed for each API

    protected virtual TimeSpan SleepDuration(int retryAttempts)
    {
        return TimeSpan.FromSeconds(Math.Pow(2,retryAttempts)) + TimeSpan.FromMilliseconds(new Random().Next(0,100));
    }

    protected virtual Task RetryAction(DelegateResult<HttpResponseMessage> response,TimeSpan timeSpan,Context capAuthContext)
    {
        return Task.CompletedTask;
    }
}

如您所见,SleepDuration方法返回一个TimeSpan,该RetryAction与重试次数成指数比例,认情况下,BaseApi方法不执行任何操作并返回完成的任务。对于每个继承var newRetryPolicy = retryPolicy(SleepDuration,RetryAction); 的API,只需创建一个重试策略即可调用

sleepDurationProvider

问题

这个解决方案很好,但是在单元测试时遇到了一个问题。对于主类功能,我只是使用它们的接口来模拟每个API。为了测试每种API的功能,我创建了真实的API对象,但是将一个不同的委托传递给它们的构造函数,该委托忽略private readonly RetryPolicyDelegate retryPolicyDummy = ( Func<int,Task> onRetryAsync ) => { return Policy.HandleResult<HttpResponseMessage>( r => !r.IsSuccessstatusCode) .Or<TaskCanceledException>() .WaitAndRetryAsync( 5,sleepDurationProvider: (retries) => { return TimeSpan.FromMilliseconds(1); },onRetryAsync: onRetryAsync ); }; 并在每次尝试之间仅等待一毫秒:

HttpClient.SendAsync

这是因为在测试TimeSpan方法在所有5次重试后均失败时会发生什么,由于认{{1 }}。但是,在使用上面显示的伪重试策略委托时,SleepDuration方法不会被调用,因此也不会经过测试。

本质上,我想测试SleepDuration方法是否应执行的操作,返回指数倍的TimeSpan值,但是当测试涉及重试的常规API逻辑时,根本不需等待任何时间,然后执行下一次重试。

我能想到的唯一解决方案是将SleepDuration方法以及认的CreateRetryPolicySleepDuration方法移到帮助程序类,以便它们可以公共访问并因此可以进行单元测试,并保留“ no wait”重试策略委托,以便对各个API进行单元测试。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)