使用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
相关产品推荐
相关产品推荐

