如何处理NUnit测试报告中同一Key对应不同类型的JSON反序列化问题?
处理NUnit测试报告中test-suite的单对象/数组兼容反序列化
针对NUnit测试报告里test-suite字段时而为单个对象、时而为数组的情况,你可以通过自定义JSON转换器的方式,让反序列化逻辑自动兼容两种格式。下面针对.NET生态里最常用的两个JSON库分别给出实现方案:
一、使用Newtonsoft.Json(Json.NET)
1. 定义基础实体类
先写出TestSuite的基础结构(根据实际报告字段调整):
public class TestSuite { public string Name { get; set; } public string Type { get; set; } // 其他需要的字段... } public class NUnitReport { // 用List<TestSuite>统一接收,配合自定义转换器 [JsonConverter(typeof(SingleOrArrayConverter<TestSuite>))] public List<TestSuite> TestSuites { get; set; } // 报告里的其他字段... }
2. 自定义转换器
创建通用的单对象/数组兼容转换器,复用性更强:
public class SingleOrArrayConverter<T> : JsonConverter<List<T>> { public override List<T> ReadJson(JsonReader reader, Type objectType, List<T> existingValue, bool hasExistingValue, JsonSerializer serializer) { var token = JToken.Load(reader); return token.Type switch { JTokenType.Array => token.ToObject<List<T>>(), JTokenType.Object => new List<T> { token.ToObject<T>() }, _ => throw new JsonSerializationException($"Unexpected token type: {token.Type}") }; } public override void WriteJson(JsonWriter writer, List<T> value, JsonSerializer serializer) { if (value.Count == 1) { serializer.Serialize(writer, value[0]); } else { serializer.Serialize(writer, value); } } }
3. 反序列化使用
直接正常调用反序列化方法即可:
var report = JsonConvert.DeserializeObject<NUnitReport>(jsonContent);
二、使用System.Text.Json(.NET Core/.NET 5+原生库)
1. 定义基础实体类
同样先定义TestSuite和报告类,注意转换器特性的区别:
public class TestSuite { public string Name { get; set; } public string Type { get; set; } // 其他字段... } public class NUnitReport { [JsonConverter(typeof(SingleOrArrayConverter<TestSuite>))] public List<TestSuite> TestSuites { get; set; } // 其他报告字段... }
2. 自定义转换器
实现System.Text.Json的转换器接口:
public class SingleOrArrayConverter<T> : JsonConverter<List<T>> { public override List<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var list = new List<T>(); if (reader.TokenType == JsonTokenType.StartArray) { while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) { var item = JsonSerializer.Deserialize<T>(ref reader, options); if (item != null) { list.Add(item); } } } else if (reader.TokenType == JsonTokenType.StartObject) { var item = JsonSerializer.Deserialize<T>(ref reader, options); if (item != null) { list.Add(item); } } else { throw new JsonException($"Unexpected token type: {reader.TokenType}"); } return list; } public override void Write(Utf8JsonWriter writer, List<T> value, JsonSerializerOptions options) { if (value.Count == 1) { JsonSerializer.Serialize(writer, value[0], options); } else { JsonSerializer.Serialize(writer, value, options); } } }
3. 反序列化使用
调用原生的反序列化方法:
var report = JsonSerializer.Deserialize<NUnitReport>(jsonContent);
三、简易替代方案(无需自定义转换器)
如果不想写转换器,也可以在报告类里用私有字段配合公共属性做转换:
public class NUnitReport { // 先接收原始的单对象或数组 private object _testSuite; // 对外暴露统一的List<TestSuite> [JsonIgnore] public List<TestSuite> TestSuites { get { return _testSuite switch { TestSuite suite => new List<TestSuite> { suite }, IEnumerable<TestSuite> suiteArray => suiteArray.ToList(), _ => new List<TestSuite>() }; } } // 让JSON序列化器映射到私有字段 [JsonPropertyName("test-suite")] public object TestSuiteRaw { get => _testSuite; set => _testSuite = value; } // 其他报告字段... }
这种方式适合快速临时处理,但复用性不如自定义转换器。
内容的提问来源于stack exchange,提问作者Milan
相关产品推荐
相关产品推荐

