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

使用MsTest测试Azure Function时WriteAsJsonAsync序列化配置异常

问题原因

测试代码中构建的ServiceProvider缺少Azure Functions Worker运行时必需的JSON序列化配置服务,导致WriteAsJsonAsync方法无法找到对应的序列化器,从而抛出异常。

解决步骤

1. 补充注册核心依赖服务

在测试代码的ServiceCollection中添加JSON序列化配置提供者和内存流管理服务,这两个是WriteAsJsonAsync正常运行的核心依赖:

ServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<ILoggerFactory, LoggerFactory>();

// 添加JSON序列化器配置服务,使用Web默认序列化规则
serviceCollection.AddSingleton<IJsonSerializerOptionsProvider>(_ => 
    new DefaultJsonSerializerOptionsProvider(new JsonSerializerOptions(JsonSerializerDefaults.Web)));

// 添加内存流管理器,WriteAsJsonAsync依赖此服务创建输出流
serviceCollection.AddSingleton<IMemoryStreamManager, MemoryStreamManager>();

ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();

2. 修正Mock验证逻辑

原代码中异步方法的验证写法错误,不需要调用.Result,直接验证方法本身的调用即可:

mockCrm2CrmBusiness.Verify(b => b.Exists(It.IsAny<Opportunity>()), Times.Never);
mockCrm2CrmBusiness.Verify(b => b.CreateOpportunity(It.IsAny<Opportunity>()), Times.Never);

3. (可选)使用官方测试包简化配置

如果不想手动注册服务,可以安装Microsoft.Azure.Functions.Worker.Testing NuGet包,使用TestFunctionContext替代手动Mock的FunctionContext,它会自动配置所有必需的运行时服务:

// 替换原有的Mock<FunctionContext>代码
var context = new TestFunctionContext();
完整修改后的测试代码
[TestMethod, TestCategory("CreateOpportunity")]
public void CreateOpportunity_OK()
{
    // Test parameters
    string testRequest = Crm2CrmTestModels.GetRequest();
    OpportunityCreateResponse testOpportunityCreateResponse = Crm2CrmTestModels.GetOpportunityCreateResponse();

    ServiceCollection serviceCollection = new ServiceCollection();
    serviceCollection.AddScoped<ILoggerFactory, LoggerFactory>();
    // 新增:添加JSON序列化和内存流服务
    serviceCollection.AddSingleton<IJsonSerializerOptionsProvider>(_ => 
        new DefaultJsonSerializerOptionsProvider(new JsonSerializerOptions(JsonSerializerDefaults.Web)));
    serviceCollection.AddSingleton<IMemoryStreamManager, MemoryStreamManager>();
    ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();

    Mock<FunctionContext> context = new Mock<FunctionContext>();
    context.SetupProperty(c => c.InstanceServices, serviceProvider);

    MemoryStream body = new MemoryStream(Encoding.ASCII.GetBytes(testRequest));
    FakeHttpRequestData request = new FakeHttpRequestData(
                    context.Object,
                    new Uri("https://test.com"),
                    body);

    // Setup mocks
    Mock<ICrm2CrmBusiness> mockCrm2CrmBusiness = new(MockBehavior.Strict);
    mockCrm2CrmBusiness.Setup(b => b.Exists(It.IsAny<Opportunity>())).ReturnsAsync(It.IsAny<string>());
    mockCrm2CrmBusiness.Setup(b => b.CreateOpportunity(It.IsAny<Opportunity>())).ReturnsAsync(testOpportunityCreateResponse);

    ICrm2CrmBusiness consentsBusiness = mockCrm2CrmBusiness.Object;

    ILogger<Crm2CrmFunction> logger = new Mock<ILogger<Crm2CrmFunction>>().Object;

    Mock<ICrm2CrmAdapter> mockCrm2CrmAdapter = new(MockBehavior.Strict);
    mockCrm2CrmAdapter.Setup(b => b.ConvertToBusiness(It.IsAny<Crm2Crm.FunctionsApp.Models.Request.Opportunity>())).Returns(It.IsAny<Opportunity>());

    ICrm2CrmAdapter crm2CrmAdapter = mockCrm2CrmAdapter.Object;

    // Execute
    Crm2CrmFunction functions = new(logger, consentsBusiness, crm2CrmAdapter);
    HttpResponseData result = functions.CreateOpportunity(httpRequest: request, context.Object).Result;

    // 修正:移除.Result,直接验证方法调用
    mockCrm2CrmBusiness.Verify(b => b.Exists(It.IsAny<Opportunity>()), Times.Never);
    mockCrm2CrmBusiness.Verify(b => b.CreateOpportunity(It.IsAny<Opportunity>()), Times.Never);

    Assert.IsNotNull(result);
    Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 14:38:19