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

Durable Functions单元测试遇SystemNotSupported异常求助

Durable Function Activity函数单元测试问题

我正在为Durable Function编排中的Activity函数编写单元测试,使用VS 2022创建的模板。尝试模拟ILogger时触发了System.NotSupportedException异常。

待测试函数代码

[Function(nameof(MyFunction))]
public static string MyFunction([ActivityTrigger] MyParameters input, FunctionContext executionContext)
{
    ILogger logger = executionContext.GetLogger("MyFunction");
    logger.LogInformation("Testing MyFunction...");

    return "It worked!";
}

测试代码(触发异常部分)

[Test]
public async Task MyFunction_ValidParameters_ReturnsValidString()
{
    // Arrange
    Mock<FunctionContext> funcContextMock = new Mock<FunctionContext>();
    funcContextMock.Setup(s => s.GetLogger(It.IsAny<string>()))
                   .Returns(Mock.Of<ILogger>);

    // Act
    string blobName = await MyClass.MyFunction(input, funcContextMock.Object);

    // Assert
    Assert.That(blobName, Is.Not.Null);
    Assert.That(blobName, Is.Not.Empty);
    Assert.That(blobName, Does.StartWith(input.ExtractName));
}

异常触发于设置GetLogger()时。我理解该异常,但未找到拦截Activity函数中Logger的方法,请问该如何实现?

另外,我了解到有人推荐使用依赖注入进行Durable Functions单元测试,能否修改现有代码实现?微软单元测试帮助页面中的方法签名与VS2022生成的差异是什么?


解决方案

一、解决GetLogger模拟异常的方法

FunctionContext.GetLogger是扩展方法,Moq无法直接模拟扩展方法,这就是触发NotSupportedException的原因。可以通过模拟FunctionContext的LoggerProvider属性间接获取Logger:

修改后的测试代码

[Test]
public void MyFunction_ValidParameters_ReturnsValidString()
{
    // Arrange
    var loggerMock = new Mock<ILogger>();
    var loggerProviderMock = new Mock<ILoggerProvider>();
    loggerProviderMock.Setup(p => p.CreateLogger(It.IsAny<string>()))
                      .Returns(loggerMock.Object);

    var funcContextMock = new Mock<FunctionContext>();
    funcContextMock.Setup(c => c.LoggerProvider)
                   .Returns(loggerProviderMock.Object);

    var input = new MyParameters { ExtractName = "test" };

    // Act
    string result = MyClass.MyFunction(input, funcContextMock.Object);

    // Assert
    Assert.That(result, Is.Not.Null);
    Assert.That(result, Is.Not.Empty);
    // 原业务返回值为"It worked!",修正断言逻辑
    Assert.That(result, Is.EqualTo("It worked!"));

    // 验证日志是否被正确调用
    loggerMock.Verify(l => l.Log(
        LogLevel.Information,
        It.IsAny<EventId>(),
        It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Testing MyFunction...")),
        It.IsAny<Exception>(),
        It.IsAny<Func<It.IsAnyType, Exception, string>>()), Times.Once);
}

二、改用依赖注入改造现有代码

VS2022默认生成静态函数,依赖注入需要将函数改为实例方法,通过构造函数注入ILogger以解耦运行时上下文:

改造后的Activity函数代码

public class MyActivityFunctions
{
    private readonly ILogger<MyActivityFunctions> _logger;

    // 构造函数注入ILogger
    public MyActivityFunctions(ILogger<MyActivityFunctions> logger)
    {
        _logger = logger;
    }

    [Function(nameof(MyFunction))]
    public string MyFunction([ActivityTrigger] MyParameters input)
    {
        _logger.LogInformation("Testing MyFunction...");
        return "It worked!";
    }
}

对应的单元测试代码

[Test]
public void MyFunction_ValidParameters_ReturnsValidString()
{
    // Arrange
    var loggerMock = new Mock<ILogger<MyActivityFunctions>>();
    var activityFunctions = new MyActivityFunctions(loggerMock.Object);
    var input = new MyParameters { ExtractName = "test" };

    // Act
    string result = activityFunctions.MyFunction(input);

    // Assert
    Assert.That(result, Is.EqualTo("It worked!"));
    // 验证日志调用
    loggerMock.Verify(l => l.Log(
        LogLevel.Information,
        It.IsAny<EventId>(),
        It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Testing MyFunction...")),
        It.IsAny<Exception>(),
        It.IsAny<Func<It.IsAnyType, Exception, string>>()), Times.Once);
}

这种方式彻底避免了对FunctionContext的依赖,单元测试逻辑更简洁,也符合现代.NET的依赖注入设计原则。

三、微软单元测试文档与VS2022模板的方法签名差异

微软官方文档中的Durable Functions单元测试示例,普遍采用实例方法+依赖注入模式:函数参数仅保留业务输入(如ActivityTrigger绑定的参数),所需的ILogger等服务通过构造函数注入,完全解耦运行时上下文。

而VS2022默认生成的Activity函数模板是静态方法,强制将FunctionContext作为参数传入,要求开发者通过上下文获取ILogger、配置等资源,这种写法更偏向快速上手,但会导致函数与运行时强绑定,降低可测试性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:37:31