Sasa Jovanovic
Sasa Jovanovic

Reputation: 334

Unit test for custom JsonConverter

In my application, I need some parts of the application where I need to have EscapeHtml to escape special characters in string, but not global.

I created a custom JsonConverter class:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;

namespace Shared
{
    public class EscapingHtmlConverter : JsonConverter
    {
        public EscapingHtmlConverter()
        {
        }

        public override bool CanRead => true;

        public override bool CanWrite => false;

        public override bool CanConvert(Type objectType) => objectType == typeof(string);

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.String)
            {
                var res = ((string)reader.Value)?.Trim() == string.Empty ? null : ((string)reader.Value)?.Trim();

                return res == null ? null : JsonConvert.SerializeObject(
                                            res,
                                            Formatting.None,
                                            new JsonSerializerSettings
                                            { StringEscapeHandling = StringEscapeHandling.EscapeHtml });
            }

            return reader.Value;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
}

and in model use attribute

[JsonConverter(typeof(EscapingHtmlConverter))]
public string PropertyName { get; set; }

I need a unit test for a custom JsonConverter and I try to do it this way:

using Xunit;
using Shared;
using System;
using System.Collections.Generic;
using System.Text;
using Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Shared.Tests
{
    public class EscapingHtmlConverterTests
    {

        [Fact()]
        public void ReadJsonTest()
        {
            Model model = new Model()
            {
                PropertyToNotBeEscaped = "Something that do not need to be escaped",
                PropertyToBeEscaped = "Some string <with> [special] 'characters' & more",                
            }; 

            var expectedResult = JsonConvert.SerializeObject(model.PropertyToBeEscaped, Formatting.None, new JsonSerializerSettings
            {
                StringEscapeHandling = StringEscapeHandling.EscapeHtml
            });

            JsonReader reader = new JTokenReader(JToken.Parse(JsonConvert.SerializeObject(model.PropertyToBeEscaped)));
            var serializer = new JsonSerializer();
            var converter = new EscapingHtmlConverter();

            // just for debugging
            Assert.NotNull(model.PropertyToBeEscaped);
            Assert.NotNull(reader);
            Assert.NotNull(serializer);

            // Act
            var result = converter.ReadJson(reader, model.propertyTobeEscaped.GetType(), "Some string <with> [special] 'characters' & more", serializer);
            Assert.Equal(expectedResult, result?.ToString());
        }
    }
}

But test failed

Message: 
Assert.Equal() Failure
Expected: "Some string \u003cwith\u003e [special] \u0027characters\u0027 \u0026 more"
Actual:   (null)

I am not sure about the last part of the test - parameters that I should pass to JsonConverter

Upvotes: 1

Views: 808

Answers (1)

Peter Csala
Peter Csala

Reputation: 22714

After performing a quick debugging it turned out that your guard expression (reader.TokenType == JsonToken.String) returns false in your test that's why the result is null

One way to fix this is by calling the reader.Read before the guard expression. I've transformed your guard expression to an early exit to streamline your code.

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    reader.Read();
    if (reader.TokenType != JsonToken.String)
       return reader.Value;
    
    ...
}

Upvotes: 2

Related Questions