繁体   English   中英

测试自定义JsonConverter时发生异常

[英]Exception when testing custom JsonConverter

我们从API获得序列化的DateTimes,格式如下: /Date(1574487012797)/为了使用System.Text.Json反序列化此值,我们编写了自己的JsonConverter

public class DateTimeConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var dateTimeString = reader.GetString();
        dateTimeString = dateTimeString.Replace("/Date(", "");
        dateTimeString = dateTimeString.Replace(")/", "");
        var epoch = Convert.ToInt64(dateTimeString);
        var dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(epoch);
        return dateTimeOffset.UtcDateTime;
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"));
    }
}

我想为此转换器编写一个单元测试。 我尝试了以下内容:

public class DateTimeConverterTest
{
    private readonly DateTimeConverter testee;

    public DateTimeConverterTest()
    {
        this.testee = new DateTimeConverter();
    }

    [Fact]
    public void Read_WhenCalledWithSerializedDateTime_ThenReturnDeserializedDateTime()
    {
        var a = "{\r\n \"PublikationsDatum\": \"/Date(1573581177000)/\" \r\n}";
        //var serializedDateTime = "/Date(1573581177000)/";
        var utf8JsonReader = new Utf8JsonReader(Encoding.UTF8.GetBytes(a), false, new JsonReaderState(new JsonReaderOptions()));
        //utf8JsonReader.TokenType = JsonTokenType.String;
        var deserializedDateTime = this.testee.Read(ref utf8JsonReader, typeof(DateTime), new JsonSerializerOptions {IgnoreNullValues = true});

    }

    private class TestClass
    {
        public DateTime PublikationsDatum { get; set; }
    }
}

不幸的是,当尝试执行单元测试时,我在var dateTimeString = reader.GetString();处收到InvalidOperationException var dateTimeString = reader.GetString();

System.InvalidOperationException:'无法以字符串形式获取令牌类型'None'的值。

如何正确设置测试/我在做什么错?

在调用JsonConverter<T>.Read()之前,必须前进Utf8JsonReader直到将其定位在"PublikationsDatum"属性的值上,例如:

public void Read_WhenCalledWithSerializedDateTime_ThenReturnDeserializedDateTime()
{
    var a = "{\r\n \"PublikationsDatum\": \"/Date(1573581177000)/\" \r\n}";
    var utf8JsonReader = new Utf8JsonReader(Encoding.UTF8.GetBytes(a), false, new JsonReaderState(new JsonReaderOptions()));
    while (utf8JsonReader.Read())
        if (utf8JsonReader.TokenType == JsonTokenType.String)
            break;
    var deserializedDateTime = this.testee.Read(ref utf8JsonReader, typeof(DateTime), new JsonSerializerOptions {IgnoreNullValues = true});
}

演示小提琴#1 在这里

另外,您可以通过解析一个简单的JSON字符串文字"/Date(1573581177000)/"来简化单元测试。 但是,您仍然需要使读取器前进一次,因为它最初位于第一个令牌的开头之前,使用utf8JsonReader.TokenType == JsonTokenType.None

public void Read_WhenCalledWithSerializedDateTime_ThenReturnDeserializedDateTime()
{
    var a = "\"/Date(1573581177000)/\"";
    var utf8JsonReader = new Utf8JsonReader(Encoding.UTF8.GetBytes(a), false, new JsonReaderState(new JsonReaderOptions()));
    // Reader always starts out without having read anything yet, so TokenType == JsonTokenType.None initially
    Assert.IsTrue(utf8JsonReader.TokenType == JsonTokenType.None);
    utf8JsonReader.Read();
    var deserializedDateTime = this.testee.Read(ref utf8JsonReader, typeof(DateTime), new JsonSerializerOptions {IgnoreNullValues = true});
}

演示小提琴#2 在这里

笔记:

  • "\\/Date(number of ticks)\\/"是Microsoft原始JavaScriptSerializer用于将DateTime序列化为JSON字符串的格式。 有关详细信息,请参见文档注释

    (在JSON 字符串文字中\\/只是一个转义的\\并且会被Utf8JsonReader默默地解释为此类,请参见此处的小提琴#3。您无需在JSON转换器中检查\\/即可处理JavaScriptSerializer生成的日期和次)。

  • DataContractSerializer使用的格式略有不同。 文档

    DateTime值以“ / Date(700000 + 0500)/”的形式显示为JSON字符串,其中第一个数字(在提供的示例中为700000)是GMT时区中的毫秒数(常规(非夏令时))从1970年1月1日午夜开始的时间。该数字可能为负值,代表较早的时间。 在示例中,由“ +0500”组成的部分是可选的,它指示时间属于本地时间-也就是说,应在反序列化时将其转换为本地时区。 如果不存在,则将时间反序列化为Utc。 实际数字(在此示例中为“ 0500”)及其符号(+或-)将被忽略。

  • Newtonsoft的DateTimeUtils.TryParseDateTimeMicrosoft()可能有助于指导您的实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM