You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否对CallActivityWithRetryAsync进行单元测试并复现重试逻辑?

解决Durable Functions中CallActivityWithRetryAsync单元测试不触发重试的问题

问题根源

CallActivityWithRetryAsync的重试逻辑由Durable Task运行时框架调度,直接Mock IDurableOrchestrationContext做单元测试时,框架的重试调度逻辑不会生效——你当前的Mock仅模拟了方法的单次调用行为,运行时不会自动发起后续重试,所以断点和日志只会触发一次。

解决方案

方案1:手动模拟多次调用(轻量适配单元测试)

既然运行时不会自动调度重试,你需要通过SetupSequence明确模拟对应次数的异常抛出,注意RetryOptions的MaxNumberOfAttempts参数包含首次调用,比如设置为3时,会有1次初始调用+2次重试,共3次调用。

修改Mock配置如下:

mockContext.SetupSequence(c => c.CallActivityWithRetryAsync(
        nameof(SerialiseXml), 
        It.IsAny<RetryOptions>(), 
        It.IsAny<InboundOrchestrationData>()))
    .ThrowsAsync(new IOException()) // 首次调用
    .ThrowsAsync(new IOException()) // 第一次重试
    .ThrowsAsync(new IOException()); // 第二次重试

测试时可验证调用次数:

mockContext.Verify(c => c.CallActivityWithRetryAsync(
        nameof(SerialiseXml), 
        It.IsAny<RetryOptions>(), 
        It.IsAny<InboundOrchestrationData>()), 
    Times.Exactly(3));

方案2:使用官方测试框架(贴近真实运行时)

若需更真实的测试环境,推荐用Durable Functions官方测试包,它会模拟运行时调度逻辑自动处理重试:

  • In-Process模型:安装Microsoft.Azure.WebJobs.Extensions.DurableTask.Testing包
  • 孤立进程模型:安装Microsoft.Azure.Functions.Worker.Extensions.DurableTask.Testing包

示例代码(In-Process模型):

// 创建测试用Orchestration主机
var host = new TestDurableOrchestrationHost();

// 注册Activity函数的模拟实现(每次调用抛异常)
host.AddActivity(nameof(SerialiseXml), (InboundOrchestrationData input) => 
    throw new IOException());

// 启动Orchestrator
var instanceId = await host.StartNewAsync(nameof(YourOrchestratorFunction), data);

// 等待Orchestrator执行完成
var status = await host.WaitForCompletionAsync(instanceId, TimeSpan.FromSeconds(30));

// 验证重试次数:检查历史记录中的失败事件数量
Assert.Equal(3, status.History.Count(h => h.EventType == EventType.ActivityFailed));

这种方式无需手动MockIDurableOrchestrationContext,测试逻辑更贴近生产环境真实行为。

内容的提问来源于stack exchange,提问作者phil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 04:21:47