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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 13:09:26