How can I unit test Custom Date Deserializer using Java

Viewed 601

I just started to learn Unit testing.

I would like to Unit test custom date deserializer which looks like this:

CustomDateDeserializer.java

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

public class CustomDateDeserializer extends JsonDeserializer {
    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {

        Long toParse = p.getLongValue();
        SimpleDateFormat format = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
        format.setTimeZone(TimeZone.getTimeZone("GMT+1"));

        String formattedActualDate = format.format(new Date(toParse));

        return formattedActualDate;
    }
}

What is the best way to test it? Any advice appreciated.

1 Answers

If I understand well, you have a JsonParser, you extract a long from it and turn it into a readable date.

Well, first, don't use Date and SimpleDateFormat: they're obsolete and the java.time API is much, much better than those. So that's what I'll use.

What you need is mocking the parameters. Both JsonParser and DeserializationContext are abstract classes so they'll be easy to mock.

And to mock, we use libraries such as Mockito or Powermock.

For the examples below, I used Mockito.

CustomDateDeserializer deserializer;
JsonParser parser;
DeserializationContext context;

@BeforeEach
void setup() {
  deserializer = new CustomDateDeserializer();
  parser = mock(JsonParser.class);
  context = mock(DeserializationContext.class);
}

@Test
void testDeserialize() {
  when(parser.getLongValue()).thenReturn(12L*60*60*1000); // 1970-01-01T12:00:00.000Z
  
  String result = deserializer.deserialize(parser, context);
  
  assertEquals("01 Jan 1970 11:00:00 GMT+1");
}

But your implementation uses deprecated API... You should use java.time instead. Also, note Java allows you to make the return-type more specific than the overridden method so let's rewrite your method as well:

class CustomDateDeserializer extends JsonDeserializer {
  static final ZoneOffset ZONE_OFFSET = ZoneOffset.of("UTC+01:00");
  static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm:ss z");

  @Override
  // Note the return-type is String, not Object
  public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
    Instant instant = Instant.ofEpochMilli(p.getLongValue());
    LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZONE_OFFSET);
    return dateTime.format(FORMATTER);
  }
}
Related