使用NSubstitute模拟Durable Task对象触发空引用异常的排查与解决
问题分析与修复方案
问题根源
- IDurableActivityContext未模拟输入返回值:测试中的
_activityCtx没有设置GetInput<EligibleMember>()的返回结果,导致业务方法里var input = ctx.GetInput<EligibleMember>()得到null,后续访问input.AccountNumber触发空引用异常。 - IEnumerable模拟不当:用
Substitute.For<IEnumerable<FulfillmentProcess>>()模拟的集合,调用ToList()时可能因枚举器未正确模拟引发问题,直接返回实际空集合更可靠。
修复后的测试用例
[Fact] public async Task CanCallTriggerTableDataAsync() { // 模拟IDurableActivityContext的GetInput方法,返回带AccountNumber的测试实例 var testMember = new EligibleMember { AccountNumber = "test-account-123" }; _activityCtx.GetInput<EligibleMember>().Returns(testMember); // 模拟服务方法返回实际空集合,避免IEnumerable模拟的潜在问题 _getAllTriggerTableService.GetAllTriggerTableDataForOe30Async(testMember.AccountNumber) .Returns(Enumerable.Empty<FulfillmentProcess>()); // 执行被测方法 var result = await _function.TriggerTableDataAsync(_activityCtx); // 验证服务方法被正确调用(用具体参数值替代Arg.Any,测试更严谨) await _getAllTriggerTableService.Received() .GetAllTriggerTableDataForOe30Async(testMember.AccountNumber); // 断言结果非空 result.Should().NotBeNull(); }
额外优化建议
- 验证时优先使用具体参数值而非
Arg.Any<string>(),确保业务方法正确传递了AccountNumber,提升测试严谨性。 - 集合类型返回值优先用
Enumerable.Empty<T>()或实际列表实例,避免模拟IEnumerable接口带来的不必要问题。
内容的提问来源于stack exchange,提问作者Nik
相关产品推荐
相关产品推荐

