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

如何对Azure函数ObjectResult的JSON序列化进行单元测试

问题解决:Azure函数.NET6进程内/隔离模式序列化差异及单元测试方案

一、序列化差异的根源与修复

.NET6 Azure函数进程内模式默认使用Newtonsoft.Json序列化,隔离模式默认使用System.Text.Json,两者默认配置差异导致了你的问题:

  • @odata.type字段变形:System.Text.Json默认不兼容Newtonsoft.Json的属性命名规则,若未显式配置,带@前缀的属性名会被错误处理
  • 空值未被忽略:System.Text.Json默认序列化空值属性,而Newtonsoft.Json默认忽略空值

修复方案(隔离模式下)

1. 全局配置System.Text.Json匹配Newtonsoft行为

在隔离模式项目的Program.cs中,配置函数的Json序列化选项,统一对齐进程内的序列化逻辑:

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults(builder =>
    {
        builder.ConfigureJsonSerializerOptions(options =>
        {
            // 序列化时忽略空值属性
            options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
            // 保留属性名原样输出,确保@odata.type不会被修改
            options.PropertyNamingPolicy = null;
        });
    })
    .Build();

host.Run();

2. 针对单个属性显式指定序列化名称

如果不需要全局修改配置,可以在Claims类的属性上添加System.Text.Json特性,强制指定序列化后的字段名:

public class Claims
{
    [JsonPropertyName("@odata.type")]
    public string? ODataType { get; set; } = "#Microsoft.Open.AzureAD.Model.CustomClaim";
    
    public string? ClaimType { get; set; }
    public string? ClaimValue { get; set; }
    public string? AnotherValue { get; set; }
}

二、单元测试:无需运行函数验证序列化结果

1. 进程内模式测试(解析IActionResult)

对于返回OkObjectResult的进程内函数,可直接提取返回对象并使用Newtonsoft.Json序列化验证:

[Test]
public void ProcessInMode_SerializesCorrectly()
{
    // 实例化函数类
    var function = new CustomClaimsProviderFunction();
    
    // 调用函数获取IActionResult
    var result = function.Run(new HttpRequestMessage());
    
    // 转换为OkObjectResult并验证非空
    var okResult = result as OkObjectResult;
    Assert.NotNull(okResult);
    
    // 使用Newtonsoft.Json序列化(匹配进程内默认行为)
    var json = JsonConvert.SerializeObject(okResult.Value, new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore,
        ContractResolver = new DefaultContractResolver()
    });
    
    // 断言序列化结果符合预期
    Assert.That(json, Does.Contain("@odata.type"));
    Assert.That(json, Does.Not.Contain("anotherValue: null"));
}

2. 隔离模式测试(验证序列化逻辑)

隔离模式函数通常返回HttpResponseData,可直接序列化要返回的对象(使用和函数一致的配置),或模拟函数上下文测试完整逻辑:

方式一:直接序列化对象验证

[Test]
public void IsolatedMode_SerializesCorrectly()
{
    // 准备测试用的Claims对象
    var claims = new Claims
    {
        ODataType = "#Microsoft.Open.AzureAD.Model.CustomClaim",
        ClaimType = "testType",
        ClaimValue = "testValue",
        AnotherValue = null
    };
    
    // 使用和函数一致的JsonSerializerOptions
    var options = new JsonSerializerOptions
    {
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
        PropertyNamingPolicy = null
    };
    
    // 序列化对象
    var json = JsonSerializer.Serialize(claims, options);
    
    // 断言结果符合要求
    Assert.That(json, Does.Contain("@odata.type"));
    Assert.That(json, Does.Not.Contain("anotherValue"));
}

方式二:模拟函数上下文测试完整流程

借助Microsoft.Azure.Functions.Worker.Testing包模拟运行环境:

[Test]
public async Task IsolatedFunction_ReturnsCorrectJson()
{
    // 创建配置好序列化选项的测试主机
    using var host = new HostBuilder()
        .ConfigureFunctionsWorkerDefaults()
        .ConfigureJsonSerializerOptions(options =>
        {
            options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
            options.PropertyNamingPolicy = null;
        })
        .Build();
    
    // 模拟HttpRequestData
    var request = TestHttpRequestData.Create(host.Services);
    
    // 实例化函数并调用
    var function = new CustomClaimsProviderIsolatedFunction();
    var response = await function.Run(request);
    
    // 读取响应内容
    var responseBody = await new StreamReader(response.Body).ReadToEndAsync();
    
    // 断言响应结果
    Assert.That(responseBody, Does.Contain("@odata.type"));
    Assert.That(responseBody, Does.Not.Contain("anotherValue: null"));
}

三、结果验证

应用修复后,隔离模式的输出将和进程内模式一致:

{
  "@odata.type": "#Microsoft.Open.AzureAD.Model.CustomClaim",
  "claimType": "testType",
  "claimValue": "testValue"
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 11:43:27