C# 单元测试睡眠持续时间轮询等待重试策略

C# 单元测试睡眠持续时间轮询等待重试策略,c#,nunit,mstest,xunit,polly,C#,Nunit,Mstest,Xunit,Polly,我想写一个单元测试,看看执行是否在指定的时间内处于休眠状态。我遇到了SystemClock,它是Polly.Utilities的一部分,但我正在寻找类似于这里提到的Polly单元测试的实现,如下所示 [Fact] public void Should_sleep_for_the_specified_duration_each_retry_when_specified_exception_thrown_same_number_of_times_as_there_are_sleep_durati

我想写一个单元测试,看看执行是否在指定的时间内处于休眠状态。我遇到了
SystemClock
,它是
Polly.Utilities
的一部分,但我正在寻找类似于这里提到的Polly单元测试的实现,如下所示

 [Fact]
 public void Should_sleep_for_the_specified_duration_each_retry_when_specified_exception_thrown_same_number_of_times_as_there_are_sleep_durations()
 {
      var totalTimeSlept = 0;

      var policy = Policy
            .Handle<DivideByZeroException>()
            .WaitAndRetry(new[]
            {
               1.Seconds(),
               2.Seconds(),
               3.Seconds()
            });

      SystemClock.Sleep = span => totalTimeSlept += span.Seconds;

      policy.RaiseException<DivideByZeroException>(3);

      totalTimeSlept.Should()
                      .Be(1 + 2 + 3);
  }
[事实]
public void应该在指定的时间内睡眠,每次重试,当指定的时间,抛出异常,相同的次数,有睡眠时间()
{
var totalTimeSlept=0;
var策略=策略
.Handle()
.WaitAndRetry(新[]
{
1.秒(),
2.秒(),
3.秒()
});
SystemClock.Sleep=span=>totaltimesleep+=span.Seconds;
政策。提出例外(3);
totalTimeSlept.Should()
.Be(1+2+3);
}
目前我的政策是

var customPolicy = Policy
                     .Handle<SqlException>(x => IsTransientError(x))
                     .WaitAndRetryAsync(
                      3,
                      (retryAttempt) => getSleepDurationByRetryAtempt(retryAttempt)
                     );
var customPolicy=Policy
.Handle(x=>IsTransientError(x))
.WaitAndRetryAsync(
3.
(RetryAttenting)=>GetSleepDurationByRetryAttenting(RetryAttenting)
);
我想测试策略的总睡眠时间。对于每次重试尝试[1,2,3],睡眠持续时间为[1,2,3]。 在所有3次重试后,总睡眠时间应为1+2+3=6。此测试与上面链接中提到的Polly规格非常相似


问题:如何编写customPolicy的单元测试,以测试与polly规范类似的总睡眠时间。我想看看编写单元测试的实现或说明。

您可以通过使用
onRetry
函数来实现这一点

为了简单起见,让我定义
IsTransientError
GetSleepDurationByRetryAttent
方法如下:

public TimeSpan getSleepDurationByRetryAttest(int尝试)=>TimeSpan.FromSeconds(尝试);
公共bool IsTransientError(SqlException ex)=>true;
顺便说一句,您可以通过避免(不必要的)匿名lambda来缩短策略定义:

var customPolicy = Policy
    .Handle<SqlException>(IsTransientError)
    .WaitAndRetryAsync(3, GetSleepDurationByRetryAttempt)
让我们把所有这些放在一起:

[事实]
public async Task GivinaCustomSleepDuration Provider \u当指定的持续时间策略超过预期的累计持续时间()时
{
//安排
var totalSleepDuration=TimeSpan.0;
var customPolicy=Policy
.Handle(IsTransientError)
.WaitAndRetryAsync(3,GetSleepDurationByRetryAtest,
onRetry:(ex,duration,ctx)=>{totalSleepDuration=totalSleepDuration.Add(duration);}
);
//表演
Func actionWithRetry=async()=>等待customPolicy.ExecuteAsync(()=>抛出新的SqlException());
//断言
_=等待Assert.ThrowsAsync(actionWithRetry);
Assert.Equal(6,totalSleepDuration.s);
}

更新#1:减少延迟并引入理论

根据您的需求,可以使用不同的参数运行相同的测试用例。这就是
Theory
InlineData
可以帮助您:

[理论]
[在线数据(3600)]
[在线数据(41000)]
[在线数据(51500)]
公共异步任务为CustomsLeeUpduration提供程序\u指定的累计持续时间(int-retryCount,int-expectedTotalSleepInMs)
{
//安排
var totalSleepDuration=TimeSpan.0;
var customPolicy=Policy
.Handle(IsTransientError)
.WaitAndRetryAsync(retryCount、GetSleepDurationByRetryAttest、,
onRetry:(ex,duration,ctx)=>{totalSleepDuration=totalSleepDuration.Add(duration);}
);
//表演
Func actionWithRetry=async()=>等待customPolicy.ExecuteAsync(()=>抛出新的SqlException());
//断言
_=等待Assert.ThrowsAsync(actionWithRetry);
Assert.Equal(TimeSpan.From毫秒(expectedTotalSleepInMs),totalSleepDuration);
}
公共静态TimeSpan GetSleepDurationByRetryAtTest(int尝试)=>TimeSpan.FromMillions(尝试*100);

更新#2:通过
上下文传递时间跨度

为了传输和检索
TimeSpan
,我们可以为此创建两种扩展方法:

公共静态类contextensions
{
私有常量字符串累加器=“持续累加器”;
公共静态上下文SetAccumulator(此上下文上下文,TimeSpan durationAccumulator)
{
上下文[累加器]=持续累加器;
返回上下文;
}
公共静态TimeSpan?GetAccumulator(此上下文)
{
if(!context.TryGetValue(累加器,输出变量ts))
返回null;
if(ts为时间间隔累加器)
回流蓄能器;
返回null;
}
}
我们还可以提取策略创建逻辑:

private异步策略GetCustomPolicy(int-retryCount)
=>政策
.Handle(IsTransientError)
.WaitAndRetryAsync(retryCount、GetSleepDurationByRetryAttest、,
onRetry:(例如,持续时间,ctx)=>
{
var totalSleepDuration=ctx.GetAccumulator();
如果(!totalSleepDuration.HasValue)返回;
totalSleepDuration=totalSleepDuration.Value.Add(持续时间);
设置累加器(totalSleepDuration.Value);
});
现在让我们(再次)将所有这些放在一起:

[理论]
[在线数据(3600)]
[在线数据(41000)]
[在线数据(51500)]
公共异步任务为CustomsLeeUpduration提供程序\u提供的自定义异步策略\u的累计持续时间是预期的(
int retryCount,int ExpectedTotalSleeps)
{
//安排
var totalSleepDuration=TimeSpan.0;
var customPolicy=GetCustomPolicy(retryCount);
var context=new context().SetAccumulator(totalSleepDuration);
//表演
Func actionWithRetry=async()=>等待customPolicy.ExecuteAsync(ctx=>thr