问题描述
当前解决方案
我有一个C#库,其中包含一个拥有多个API并以各种方式利用所有API的主类。每个API都将其HttpClient.SendAsync
包装在Polly AsyncPolicy.ExecuteAsync
中。通过在主类CreateRetryPolicy
中调用一个需要两个委托sleepDurationProvider
和onRetryAsync
的方法来创建此异步策略:
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类继承)实现为受保护的方法SleepDuration
和RetryAction
:
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
方法以及默认的CreateRetryPolicy
和SleepDuration
方法移到帮助程序类,以便它们可以公共访问并因此可以进行单元测试,并保留“ no wait”重试策略委托,以便对各个API进行单元测试。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)