Unit testing 如何在Poly重试策略中捕获最后一次尝试结果?

Unit testing 如何在Poly重试策略中捕获最后一次尝试结果?,unit-testing,.net-core,polly,Unit Testing,.net Core,Polly,我正在扩展.NETCore中的TestMethod属性。我使用Polly库进行重试逻辑以及外部超时策略 我想要一个助手方法,它可以重试调用ITestMethod,直到它通过。我不介意重试的次数。但我会设定一个必须完成的超时时间。如果委托在超时时间内成功执行,则可以。但是,如果存在超时异常,我仍然需要失败的结果值(上次迭代的结果),而不是TimeOutRejectedException或返回类型的默认值 下面是我的扩展测试方法属性类: 公共密封类GuarantedPassTestMethodAtt

我正在扩展.NETCore中的
TestMethod
属性。我使用Polly库进行重试逻辑以及外部超时策略

我想要一个助手方法,它可以重试调用
ITestMethod
,直到它通过。我不介意重试的次数。但我会设定一个必须完成的超时时间。如果委托在超时时间内成功执行,则可以。但是,如果存在超时异常,我仍然需要失败的结果值(上次迭代的结果),而不是
TimeOutRejectedException
或返回类型的默认值

下面是我的扩展测试方法属性类:

公共密封类GuarantedPassTestMethodAttribute:TestMethodAttribute
{
/// 
公共重写TestResult[]执行(ITestMethod testMethod)
{
返回ExecuteTestTillSuccess(testMethod);
}
私有测试结果[]ExecuteTestTillSuccess(ITestMethod testMethod)
{
var gracefulTestRun=
TestExecutionHelper.ExecuteTestTillPassAsync(
()=>TestInvokeDelegate(testMethod));
返回gracefulTestRun.Result;
}
私有任务TestInvokeDelegate(ITestMethod testMethod)
{
TestResult[]结果=null;
var线程=新线程(()=>result=Invoke(testMethod));
thread.Start();
thread.Join();
返回Task.FromResult(结果);
}
}
下面是我使用Polly的
TestExecutionHelper

内部静态类TestExecutionHelper
{
私有静态只读函数TestFailurePredicate=
结果=>results!=null&&
结果。长度==1&&
results.First().output!=UnitTestOutput.Passed;
内部静态异步任务ExecuteTestTillPassAsync(
Func testInvokeDelegate,
int DELAYBETWEENEXECUTIONNMS=3000,
整数时间(秒=60*10)
{
var timeoutPolicy=Policy.TimeoutAsync(timeoutingseconds);
var retryPolicy=Policy.HandleResult(TestFailurePredicate)
.WaitAndRetryAsync(int.MaxValue,x=>TimeSpan.Fromms(DelayBetweenExecutionNMs));
var testRunPolicy=timeoutPolicy.WrapAsync(retryPolicy);
返回wait wait testRunPolicy.ExecuteAsync(testInvokeDelegate);
}
}
通过此设置,我可以获得通过的测试方法执行,或者获得失败测试的
TimeOutRejectedException
。我想捕获失败测试的
TestResult
,即使在重试之后也是如此。

测试用例 假设我们有以下测试:

[TestClass]
公共类UnitTest1
{
专用静态整数计数器;
[GuaranteedPassTestMethod]
公共异步任务TestMethod1()
{
等待任务。延迟(1000);
Assert.Fail($“第{++counter}次失败”);
}
}
我使用了一个
静态
变量(称为
计数器
)来更改每个测试运行的输出

属性 我通过使用
任务简化了属性的代码。运行

公共密封类GuarantedPassTestMethodAttribute:TestMethodAttribute
{
公共重写TestResult[]执行(ITestMethod testMethod)
=>TestExecutionHelper
.ExecuteTestTillPassAsync(
async()=>等待任务。运行(
()=>testMethod.Invoke(null)))
.GetAwaiter().GetResult();
}
为了更好地处理异常,我还将
.Result
更改为
GetAwaiter().GetResult()

  • 如果您不熟悉此模式,请阅读
策略 我引入了一个名为
Results
的累加器变量,在这里我捕获了所有测试运行的结果

内部静态类TestExecutionHelper
{
私有静态只读列表结果=新列表();
私有静态只读函数TestFailurePredicate=result=>
{ 
结果。添加(结果);
返回结果!=null&&result.output!=UnitTestOutput.Passed;
};
内部静态异步任务ExecuteTestTillPassAsync(
Func testInvokeDelegate,
int DELAYBETWEENEXECUTIONNMS=3000,
int TIMEOUTINES=1*10)
{
var timeoutPolicy=Policy.TimeoutAsync(timeoutingseconds);
var retryPolicy=Policy.HandleResult(TestFailurePredicate)
.WaitAndRetryForeverAsync(=>TimeSpan.fromMillimes(delaybetweenExecutionNMs));
var testRunPolicy=timeoutPolicy.WrapAsync(retryPolicy);
请尝试{等待testRunPolicy.ExecuteAsync(testInvokeDelegate);}
catch(TimeoutRejectedException){}//Suppress
返回结果。ToArray();
}
}
  • 我在这里使用了
    WaitAndRetryForeverAsync
    而不是
    WaitAndRetryAsync(int.MaxValue,
  • 我还更改了
    testInvokeDelegate
    的签名以与界面对齐
输出 在我的测试中,我已经将默认值
timeoutingseconds
减少到10秒

 TestMethod1
   Source: UnitTest1.cs line 17

Test has multiple result outcomes
   3 Failed

Results

    1)  TestMethod1
      Duration: 1 sec

      Message: 
        Assert.Fail failed. Failed for 1th time
      Stack Trace: 
        UnitTest1.TestMethod1() line 20
        ThreadOperations.ExecuteWithAbortSafety(Action action)

    2)  TestMethod1
      Duration: 1 sec

      Message: 
        Assert.Fail failed. Failed for 2th time
      Stack Trace: 
        UnitTest1.TestMethod1() line 20
        ThreadOperations.ExecuteWithAbortSafety(Action action)

    3)  TestMethod1
      Duration: 1 sec

      Message: 
        Assert.Fail failed. Failed for 3th time
      Stack Trace: 
        UnitTest1.TestMethod1() line 20
        ThreadOperations.ExecuteWithAbortSafety(Action action)
让我们看看此测试运行的时间表:

  • 0>>1:
    TestMethod1
    Delay
  • 1:
    Assert.Fail
  • 1>>4:重试的惩罚
  • 4>>5:
    TestMethod1
    Delay
  • 5:
    Assert.Fail
  • 5>>8:重试的惩罚
  • 8>>9:
    TestMethod1
    Delay
  • 9:
    Assert.Fail
  • 9>>12::重试的惩罚
  • 10:超时开始了
这里有一点需要注意:测试持续时间不包含重试的惩罚延迟:


能否请您详细说明此代码
Invoke(testMethod)
?正如我所能
testMethod.Invoke
确实存在,但它返回一个
TestResult
@Mani这个版本对您有用吗?