C#单元测试中如何忽略顺序比较两个含JSON结构的列表
在C#单元测试中忽略顺序比较包含JSON结构的列表
嘿,这个场景我在做单元测试时经常碰到!要忽略列表元素顺序比较两个包含JSON结构的列表,有几个实用的方案,我给你拆解一下:
方案1:强类型映射+自定义相等比较器(无第三方依赖)
如果你的JSON结构是固定的,最好先把列表映射到强类型实体类,再通过自定义比较器判断元素是否相等,最后验证两个列表的元素集合一致。
步骤1:定义实体类映射JSON结构
public class PartData { public ObjectId _id { get; set; } public string PartName { get; set; } public decimal? MAP { get; set; } public string MPN { get; set; } public bool IsActive { get; set; } public string Gtin { get; set; } }
步骤2:实现自定义相等比较器
public class PartDataEqualityComparer : IEqualityComparer<PartData> { public bool Equals(PartData x, PartData y) { if (x == null && y == null) return true; if (x == null || y == null) return false; // 逐个比较所有属性,确保完全匹配 return x._id == y._id && x.PartName == y.PartName && x.MAP == y.MAP && x.MPN == y.MPN && x.IsActive == y.IsActive && x.Gtin == y.Gtin; } public int GetHashCode(PartData obj) { // 组合所有属性的哈希值,确保相等的对象哈希值一致 return HashCode.Combine(obj._id, obj.PartName, obj.MAP, obj.MPN, obj.IsActive, obj.Gtin); } }
步骤3:在单元测试中验证
有两种验证方式:
- 方式A:先排序再用
SequenceEqual比较
var sortedDbValues = DBvalues.OrderBy(item => item._id).ToList(); var sortedExcelValues = actualExcelvalues.OrderBy(item => item._id).ToList(); Assert.IsTrue(sortedDbValues.SequenceEqual(sortedExcelValues, new PartDataEqualityComparer()));
- 方式B:验证元素数量相同且每个元素都存在于另一个列表
Assert.AreEqual(DBvalues.Count, actualExcelvalues.Count); Assert.IsTrue(DBvalues.All(dbItem => actualExcelvalues.Any(excelItem => new PartDataEqualityComparer().Equals(dbItem, excelItem))));
方案2:动态JSON序列化比较(适合无强类型场景)
如果不想定义实体类,可以通过Newtonsoft.Json(Json.NET)序列化时排序属性,再将数组元素排序后比较JSON字符串。
实现代码
using Newtonsoft.Json; using Newtonsoft.Json.Linq; // 自定义序列化解析器,确保属性按名称排序 public class OrderedContractResolver : DefaultContractResolver { protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) { return base.CreateProperties(type, memberSerialization) .OrderBy(p => p.PropertyName) .ToList(); } } // 序列化配置 var serializerSettings = new JsonSerializerSettings { Formatting = Formatting.None, ContractResolver = new OrderedContractResolver() }; // 将列表转为JArray,排序后再序列化 var dbJArray = JArray.Parse(JsonConvert.SerializeObject(DBvalues, serializerSettings)); var excelJArray = JArray.Parse(JsonConvert.SerializeObject(actualExcelvalues, serializerSettings)); var sortedDbJson = JsonConvert.SerializeObject(dbJArray.OrderBy(item => item.ToString(serializerSettings))); var sortedExcelJson = JsonConvert.SerializeObject(excelJArray.OrderBy(item => item.ToString(serializerSettings))); // 比较最终的JSON字符串 Assert.AreEqual(sortedDbJson, sortedExcelJson);
方案3:用FluentAssertions框架(最简洁)
如果可以引入第三方测试库,FluentAssertions是单元测试的利器,自带忽略元素顺序的断言方法,代码极其简洁。
步骤1:安装NuGet包
在NuGet包管理器中安装FluentAssertions。
步骤2:编写测试断言
如果是强类型列表:
using FluentAssertions; DBvalues.Should().BeEquivalentTo(actualExcelvalues, options => options.ComparingByMembers<PartData>());
如果是动态JObject列表:
using FluentAssertions; using Newtonsoft.Json.Linq; var dbJObjects = DBvalues.Select(item => JObject.FromObject(item)).ToList(); var excelJObjects = actualExcelvalues.Select(item => JObject.FromObject(item)).ToList(); dbJObjects.Should().BeEquivalentTo(excelJObjects);
总结
- 追求无依赖:选方案1;
- 动态JSON场景:选方案2;
- 追求代码简洁、可读性高:强烈推荐方案3,FluentAssertions的断言语法非常直观,还能给出详细的不匹配信息。
内容的提问来源于stack exchange,提问作者Mrunal




