微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决用于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 举报,一经查实,本站将立刻删除。