Newtonsoft.Json序列化:JSON数值类型识别错误及单元测试问题
JSON序列化/反序列化适配问题解决方案
1. 可以强制指定字段以浮点数类型导入
有两种可靠的实现方式:
全局配置统一处理
在反序列化时通过JsonSerializerSettings强制将所有数值解析为double,不管JSON中是整数还是小数格式:
var serializerSettings = new JsonSerializerSettings { FloatParseHandling = FloatParseHandling.Double }; var actualModel = JsonConvert.DeserializeObject<JsonContainer>(expectedJson, serializerSettings);
针对单个字段精准处理
如果只需要特定字段按浮点数解析,给DTO字段添加JsonConverter特性:
public class Tax { [JsonProperty("tax", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(DoubleConverter))] public double? Tax; }
至于大小写命名问题,你已经通过[JsonProperty("tax")]完成了C# PascalCase与JSON小写字段的映射,这个方案完全可行,无需额外调整。
2. 当前单元测试方法存在缺陷
问题出在反序列化→序列化后的JToken对比逻辑:JSON原始的整数(如65)会被反序列化为double类型,再序列化会变成65.0,导致前后JToken的数值类型(一个是JTokenType.Integer,一个是JTokenType.Float)不一致,触发断言失败。
优化方案:调整断言逻辑
利用FluentAssertions的灵活配置,忽略数值类型差异,只验证值的等价性:
actual.Should().BeEquivalentTo(expected, options => options.Using<JValue>(ctx => { if ((ctx.Subject.Type == JTokenType.Float && ctx.Expectation.Type == JTokenType.Integer) || (ctx.Subject.Type == JTokenType.Integer && ctx.Expectation.Type == JTokenType.Float)) { Convert.ToDouble(ctx.Subject).Should().Be(Convert.ToDouble(ctx.Expectation)); } else { ctx.Subject.Should().Be(ctx.Expectation); } }).WhenTypeIs<JValue>());
替代思路:直接验证DTO对象
跳过序列化回JSON的步骤,直接从原始JToken中提取预期值,与反序列化后的DTO属性做对比,彻底规避类型表示差异问题:
var expectedTaxValue = (double)expected.SelectToken("$.Tax.tax"); actualModel.Tax.Tax.Should().Be(expectedTaxValue);
内容的提问来源于stack exchange,提问作者Fysicus
相关产品推荐
相关产品推荐

