测试自定义JsonConverter时发生异常 [英] Exception when testing custom JsonConverter

查看:68
本文介绍了测试自定义JsonConverter时发生异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We get serialized DateTimes from an API in a strange format like this: /Date(1574487012797)/ To deserialize this value with System.Text.Json, we wrote our own 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"));
    }
}

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

I'd like to write a Unit Test for this converter. What I tried is the following:

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

Unfortunately, when trying to execute the Unit Test, I get an InvalidOperationException at var dateTimeString = reader.GetString();

System.InvalidOperationException:'无法获得令牌类型'None'的值作为字符串.'

System.InvalidOperationException: 'Cannot get the value of a token type 'None' as a string.'

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

How can I setup the test correctly / what am I doing wrong?

推荐答案

在您可以调用属性的值上,例如像这样:

Before you can call JsonConverter<T>.Read() you must advance the Utf8JsonReader until it is positioned on the value of the "PublikationsDatum" property, e.g. like so:

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:

Alternatively, you could simplify your unit test by parsing a simple JSON string literal "/Date(1573581177000)/". However, you will still need to advance the reader once because it is initially positioned before the beginning of the first token, with 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字符串的格式.请参阅文档备注以获取详细信息.

  • "\/Date(number of ticks)\/" is the format used by Microsoft's original JavaScriptSerializer for serializing a DateTime to a JSON string. See the documentation remarks for details.

(在JSON 字符串文字中,\/只是一个转义符\,并且会被Utf8JsonReader默默地解释,请参见小提琴#3 此处.需要在JSON转换器中检查\/以处理JavaScriptSerializer生成的日期和时间.)

(Within a JSON string literal, \/ is just an escaped \ and will be silently interpreted as such by Utf8JsonReader, see fiddle #3 here. You don't need to check for \/ within your JSON converter to handle JavaScriptSerializer generated dates and times.)

DataContractSerializer使用的格式略有不同.从 docs :

DataContractSerializer used a slightly different format. From the docs:

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

DateTime values appear as JSON strings in the form of "/Date(700000+0500)/", where the first number (700000 in the example provided) is the number of milliseconds in the GMT time zone, regular (non-daylight savings) time since midnight, January 1, 1970. The number may be negative to represent earlier times. The part that consists of "+0500" in the example is optional and indicates that the time is of the Local kind - that is, should be converted to the local time zone on deserialization. If it is absent, the time is deserialized as Utc. The actual number ("0500" in this example) and its sign (+ or -) are ignored.

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

  • Newtonsoft's implementation of DateTimeUtils.TryParseDateTimeMicrosoft() may be helpful in guiding your implementation.

    这篇关于测试自定义JsonConverter时发生异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆