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

如何在C# Web API中为JSON Schema验证编写xUnit单元测试

xUnit单元测试JSON Schema验证逻辑指南

第一步:重构验证逻辑(解耦数据库依赖)

先把原API里的验证逻辑抽成独立方法,避免直接依赖数据库查询,方便测试时传入自定义的Schema:

using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using JsonSchema.Net; // 按实际引用的Schema库调整

public class JsonSchemaValidator
{
    // 抽离验证逻辑,接收输入JSON和Schema JSON字符串
    public async Task<ICollection<ValidationError>> ValidateJsonAsync(string inputJson, string schemaJson)
    {
        var schema = await JsonSchema.FromJsonAsync(schemaJson);
        var jsonToken = JToken.Parse(inputJson);
        return schema.Validate(jsonToken).ToList();
    }
}

原API代码可改为调用该方法:

// 从数据库获取schemaJson(业务代码逻辑)
var schemaJson = await _dbContext.Schemas.FirstAsync(s => s.Id == schemaId);
var validator = new JsonSchemaValidator();
var errors = await validator.ValidateJsonAsync(inputfromAPI, schemaJson);

if (errors.Count > 0)
{
    return BadRequest(errors);
}
// 后续业务逻辑

第二步:编写xUnit测试案例

测试1:符合Schema的JSON验证通过

using Xunit;
using System.Threading.Tasks;

public class JsonSchemaValidatorTests
{
    private readonly JsonSchemaValidator _validator = new JsonSchemaValidator();

    [Fact]
    public async Task ValidateJsonAsync_ValidJsonAgainstSchema_ReturnsNoErrors()
    {
        // 模拟Schema:要求必须有"name"字符串和"age"数字字段
        var mockSchema = @"{
            ""type"": ""object"",
            ""properties"": {
                ""name"": { ""type"": ""string"" },
                ""age"": { ""type"": ""integer"" }
            },
            ""required"": [""name"", ""age""]
        }";

        // 符合Schema的输入JSON
        var validInput = @"{
            ""name"": ""Alice"",
            ""age"": 30
        }";

        var errors = await _validator.ValidateJsonAsync(validInput, mockSchema);
        Assert.Empty(errors);
    }
}

测试2:不符合Schema的JSON返回错误

[Fact]
public async Task ValidateJsonAsync_InvalidJsonAgainstSchema_ReturnsErrors()
{
    var mockSchema = @"{
        ""type"": ""object"",
        ""properties"": {
            ""name"": { ""type"": ""string"" },
            ""age"": { ""type"": ""integer"" }
        },
        ""required"": [""name"", ""age""]
    }";

    // 输入缺少必填的"age"字段
    var invalidInput = @"{
        ""name"": ""Bob""
    }";

    var errors = await _validator.ValidateJsonAsync(invalidInput, mockSchema);
    Assert.NotEmpty(errors);
    Assert.Contains(errors, e => e.Message.Contains("Required properties are missing from object: age"));
}

测试3:无效JSON输入抛出异常

[Fact]
public async Task ValidateJsonAsync_InvalidJsonInput_ThrowsException()
{
    var mockSchema = @"{ ""type"": ""object"" }";
    // 格式错误的JSON(缺少闭合括号)
    var invalidJson = @"{ ""name"": ""Charlie"" ";

    await Assert.ThrowsAsync<Newtonsoft.Json.JsonReaderException>(() => 
        _validator.ValidateJsonAsync(invalidJson, mockSchema));
}

测试4:无效Schema抛出异常

[Fact]
public async Task ValidateJsonAsync_InvalidSchema_ThrowsException()
{
    // 格式错误的Schema(缺少闭合括号)
    var invalidSchema = @"{ ""type"": ""object"" ";
    var validJson = @"{ ""name"": ""Dave"" }";

    await Assert.ThrowsAsync<JsonSchemaException>(() => 
        _validator.ValidateJsonAsync(validJson, invalidSchema));
}

关键说明

  • 测试时直接手写模拟的Schema JSON字符串,完全脱离数据库依赖,保证单元测试的隔离性
  • 用async/await替代原代码中的.Result,避免异步操作死锁,符合异步编程规范
  • 覆盖核心场景:合法输入、非法输入、无效JSON、无效Schema,确保验证逻辑的稳定性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 19:23:12