如何为用于JSON反序列化的DTO类添加代码覆盖率测试?
如何为用于JSON反序列化的DTO类添加代码覆盖率测试?
兄弟,我懂你这种困惑!刚接触测试的时候,看到DTO这种全是属性的类,真的会懵——这玩意儿有啥好测的?但其实SonarCloud提示的覆盖率问题,刚好是个契机,让我们顺便验证JSON序列化/反序列化的正确性,一举两得!
下面给你几个实用的测试方向,都是针对你这种带JsonDerivedType的DTO场景的:
1. 测试JSON反序列化到对应子类的正确性
这是最核心的测试,既能覆盖DTO的所有属性,又能验证你加的JsonDerivedType特性是否生效——毕竟类型判别器要是写错了,反序列化直接就炸了。
举个xUnit的测试例子,你可以直接套用到你的代码里:
using Xunit; using System.Text.Json; public class VehicleDtoDeserializationTests { [Fact] public void TrolleyDto_Deserialize_FromValidJson_MapsAllPropertiesCorrectly() { // 构造符合TrolleyDto结构的JSON,注意要带上typeDiscriminator var trolleyJson = @" { ""$type"": ""trolley"", ""Name"": ""Cargo Trolley 001"", ""CreationDate"": ""2024-05-20"", ""ExtendedData"": { ""Capacity"": 150, ""WheelsCount"": 4 } }"; // 执行反序列化 var vehicle = JsonSerializer.Deserialize<VehicleBaseDto>(trolleyJson, new JsonSerializerOptions { PropertyNameCaseInsensitive = true // 适配JSON的大小写问题 }); // 先验证反序列化出来的是正确的子类 Assert.IsType<TrolleyDto>(vehicle); var trolley = (TrolleyDto)vehicle; // 验证基础属性 Assert.Equal("Cargo Trolley 001", trolley.Name); Assert.Equal("2024-05-20", trolley.CreationDate); // 验证ExtendedData的属性(假设TrolleyOptions有这两个属性) Assert.NotNull(trolley.ExtendedData); Assert.Equal(150, trolley.ExtendedData.Capacity); Assert.Equal(4, trolley.ExtendedData.WheelsCount); } }
2. 测试序列化DTO到JSON的正确性
反过来,把DTO实例序列化成JSON,既能覆盖属性的getter方法(提升覆盖率),又能确认输出的JSON包含正确的字段和类型判别器,避免前端或者下游服务解析出错。
示例代码:
[Fact] public void ScooterDto_Serialize_ToJson_IncludesAllRequiredFields() { // 创建一个ScooterDto实例 var scooter = new ScooterDto { Name = "City Scooter 007", CreationDate = "2024-05-21", ExtendedData = new ScooterOptions { MaxSpeed = 30, BatteryLevel = 85 } }; // 序列化成JSON var jsonOutput = JsonSerializer.Serialize<VehicleBaseDto>(scooter); // 验证输出的JSON包含必要内容 Assert.Contains(@"Name"":""City Scooter 007""", jsonOutput); Assert.Contains(@"CreationDate"":""2024-05-21""", jsonOutput); Assert.Contains(@"$type"":""scooter""", jsonOutput); // 确认类型判别器正确输出 Assert.Contains(@"MaxSpeed"":30", jsonOutput); Assert.Contains(@"BatteryLevel"":85", jsonOutput); }
3. 测试边界情况(默认值、空值)
你的DTO里Name属性有默认值string.Empty,这种细节也可以测,既能覆盖属性的初始化逻辑,又能验证反序列化时的默认值是否生效。
示例:
[Fact] public void VehicleBaseDto_Deserialize_MissingNameField_UsesDefaultEmptyString() { var baseVehicleJson = @" { ""$type"": ""base"", ""CreationDate"": ""2024-05-22"" }"; var result = JsonSerializer.Deserialize<VehicleBaseDto>(baseVehicleJson); // 验证Name属性用了默认值 Assert.Equal(string.Empty, result.Name); Assert.Equal("2024-05-22", result.CreationDate); }
小技巧:用理论测试减少重复代码
如果每个子类都写一遍类似的测试会很繁琐,你可以用xUnit的Theory加InlineData,把不同的JSON字符串、期望类型、验证逻辑打包成参数,一次测试覆盖所有子类:
[Theory] [InlineData(@"{""$type"":""scooter"",""Name"":""Test Scooter"",""CreationDate"":""2024-05-20""}", typeof(ScooterDto))] [InlineData(@"{""$type"":""forklift"",""Name"":""Test Forklift"",""CreationDate"":""2024-05-20""}", typeof(ForkliftDto))] public void VehicleDto_Deserialize_CorrectlyMapsToSubtype(string json, Type expectedType) { var result = JsonSerializer.Deserialize<VehicleBaseDto>(json); Assert.IsType(expectedType, result); Assert.Equal("Test " + expectedType.Name.Replace("Dto", ""), result.Name); }
这样既省了代码,又能一次性覆盖所有子类的类型判别器逻辑,覆盖率直接拉满!
备注:内容来源于stack exchange,提问作者wutangcodeclan
相关产品推荐
相关产品推荐

