C# xUnit测试Azure Function时ProcessCall未调用问题
问题根因
- Mock对象使用逻辑错误:测试中传入Processor的是Moq生成的
IHandler<Request>动态代理对象,不是你编写的真实Handler<Request>实现。这个代理对象默认不会执行任何业务逻辑,所有异步方法只会直接返回完成状态的空Task,根本不会走到Handler内部调用仓储的代码。同时你初始化的_RepositoryMock从来没有注入到任何Handler实例中,自然不可能捕获到GetCodeFinder的调用。 - 方法签名不统一:你贴的代码里三处方法名完全不一致:
IHandler<TCode>接口定义的方法是ProcessCallouts,Handler实现类里写的方法是Process,Function Run方法里调用的是ProcessCall,正常情况下这种代码无法编译通过,属于笔误,需要先对齐所有方法的签名。 - 测试边界混淆:你当前写的是Processor类的单元测试,单元测试的职责是验证当前类本身的逻辑,也就是Processor是否正确调用了注入的IHandler依赖、传参是否正确。验证Handler内部是否调用仓储,是Handler类单元测试的覆盖范围,不应该在Processor的测试里跨层验证。
解决方案
根据你的测试目标分两种情况处理:
方案1:编写符合分层规范的Processor单元测试
只验证Processor本身的逻辑,不关心Handler内部实现,代码修改如下:
public class ProcessorTests { private readonly Mock<IHandler<Request>> _classifier = new Mock<IHandler<Request>>(); private Processor GetTestInstance() { return new Processor(_classifier.Object); } [Fact] public async Task Run_Method_Should_Call_Handler_With_Correct_Parameters() { // 先统一所有位置的方法名,比如接口、实现、调用处都用ProcessCallouts var sut = GetTestInstance(); var expectedTimeSpan = new TimeSpan(0, 4, 30); await sut.Run(null); // 验证Handler方法被正确调用,入参符合预期 _classifier.Verify(x => x.ProcessCallouts( It.Is<IEnumerable<string>>(codes => codes.SequenceEqual(new[] {"AR"})), 100, expectedTimeSpan ), Times.Once); } }
方案2:编写集成测试,验证从Function到仓储的全链路调用
这种场景下不要Mock IHandler,直接初始化真实的Handler实例,把Mock的依赖注入进去,再传给Processor:
public class ProcessorIntegrationTests { private readonly Mock<IRepository> _repositoryMock = new Mock<IRepository>(); private readonly Mock<IServiceV2<Code, Request>> _serviceMock = new Mock<IServiceV2<Code, Request>>(); private readonly IHandler<Request> _classifier; public ProcessorIntegrationTests() { // 用真实Handler实现,注入Mock的外部依赖 _classifier = new Handler<Request>(_repositoryMock.Object, _serviceMock.Object); } private Processor GetTestInstance() { return new Processor(_classifier); } [Fact] public async Task Run_Method_Should_Trigger_Repository_GetCodeFinder_Call() { SetupRepositoryMock(); var sut = GetTestInstance(); await sut.Run(null); _repositoryMock.Verify(x => x.GetCodeFinder( It.IsAny<IList<string>>(), It.IsAny<DateTimeOffset>(), It.IsAny<string>(), It.IsAny<int>() ), Times.Once); } private void SetupRepositoryMock() { _repositoryMock .Setup(m => m.GetCodeFinder(It.IsAny<IList<string>>(), It.IsAny<DateTimeOffset>(), It.IsAny<string>(), It.IsAny<int>())) .ReturnsAsync(new Response<Call>(false, null, Enumerable.Empty<CallOut>())); } }
额外提示:你贴出的Handler实现代码中,调用
GetCodeFinder时传入的code、time、pageToken三个变量没有在方法内定义,需要补全对应逻辑,否则运行时会抛出编译错误或运行时异常。
内容的提问来源于stack exchange,提问作者mydemo
相关产品推荐
相关产品推荐

