Kra*_*zek 9 .net c# nunit unit-testing json.net
我有一个 json 有效负载,我想以一种非平凡的方式反序列化。
{
"destinationId": 123
}
Run Code Online (Sandbox Code Playgroud)
目标类是
public class SomeObject
{
public Destination Destination { get; set; }
}
public class Destination
{
public Destination(int destinationId)
{
Id = destinationId;
}
public int Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
为了能够做到这一点,我创建了一个JsonConverter照顾它的人。
这是 ReadJson 方法:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (CanConvert(objectType))
{
var value = reader.Value;
if (value is long v)
{
// TODO: this might overflow
return new Destination((int)v);
}
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
然后我用一个[JsonConverter]接受typeof(DestinationConverter).
这在我使用时可以正常工作JsonConvert.DeserializeObject<SomeObject>(myString)(请参阅下面的单元测试),但是我在为JsonConverter特定对象创建成功的单元测试时遇到了问题(请参阅下面的第二个测试)。
[Test, AutoData]
public void SomeObject_is_correctly_deserialized(SomeObject testObject)
{
var json = $@"{{""destinationId"":{testObject.Destination.Id}}}";
Console.WriteLine($"json: {json}");
var obj = JsonConvert.DeserializeObject<SomeObject>(json);
Assert.That(obj.Destination.Id, Is.EqualTo(testObject.Destination.Id));
}
[Test, AutoData]
public void ReadJson_can_deserialize_an_integer_as_Destination(DestinationConverter sut, int testValue)
{
JsonReader reader = new JTokenReader(JToken.Parse($"{testValue}"));
var obj = sut.ReadJson(reader, typeof(Destination), null, JsonSerializer.CreateDefault());
var result = obj as Destination;
Assert.That(result, Is.Not.Null);
Assert.That(result, Is.InstanceOf<Destination>());
Assert.That(result.Id, Is.EqualTo(testValue));
}
Run Code Online (Sandbox Code Playgroud)
我一直在寻找一种方法来正确地对转换后的单元进行单元测试,但我只找到了使用整体DeserializeObject而不是仅仅测试转换器的人的例子。
PS:我在 .NET Fiddle 中粘贴了所有必要的代码:https : //dotnetfiddle.net/oUXi6k
您的基本问题是,当您创建 a 时JsonReader,它最初位于第一个标记之前。这是在文档中JsonToken提到的:
JsonToken 枚举
指定 JSON 令牌的类型。
会员
None:0如果尚未调用读取方法,则由 JsonReader 返回。
因此,要正确地对转换器进行单元测试,您需要将读取器推进到您尝试读取的 c# 对象的第一个标记,例如:
JsonReader reader = new JsonTextReader(new StringReader(json));
while (reader.TokenType == JsonToken.None)
if (!reader.Read())
break;
var obj = sut.ReadJson(reader, typeof(Destination), null, JsonSerializer.CreateDefault());
Run Code Online (Sandbox Code Playgroud)
示例小提琴在这里。
完成后,我建议您按如下方式重写转换器:
public class DestinationConverter : JsonConverter
{
public override bool CanConvert(System.Type objectType)
{
return objectType == typeof(Destination);
}
public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
var id = serializer.Deserialize<int?>(reader);
if (id == null)
return null;
return new Destination(id.Value);
}
public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
// WriteJson() is never called with a null value, instead Json.NET writes null automatically.
writer.WriteValue(((Destination)value).Id);
}
}
Run Code Online (Sandbox Code Playgroud)
通过调用serializer.Deserialize<int?>(reader)inside ReadJson(),您可以保证:
null 在读取期间处理值。
如果 JSON 格式不正确(例如截断的文件),则会抛出异常。
如果 JSON 无效(例如需要整数的对象,或整数溢出),则会抛出异常。
读取器将正确定位在正在读取的令牌的末尾。(在令牌是原语的情况下,读取器不需要高级,但对于更复杂的令牌,它需要。)
示例小提琴 #2在这里。
您可能还想增强单元测试以检查:
读取器被正确定位在 之后ReadJson(),例如通过断言TokenType和Depth是正确的,或者甚至计算JSON 流中剩余的令牌数量并断言它是预期的。
编写转换器时的一个常见错误是在转换后让读取器定位错误。完成此操作后,对象本身将被成功读取,但所有后续对象都将损坏。ReadJson()除非您断言读者之后正确定位,否则直接单元测试不会捕捉到这一点。
对于格式不正确的 JSON 流,例如被截断的流,将引发异常。
对于意外的 JSON 标记会引发异常,例如,当遇到预期原始值的数组时。
| 归档时间: |
|
| 查看次数: |
4575 次 |
| 最近记录: |