如何对Jackson JsonSerializer和JsonDeserializer进行单元测试

gue*_*gue 36 unit-testing jackson

我为我的应用程序编写了自定义JsonSerializer和JsonDeserializer.现在我想为它们编写一些单元测试.

干净的测试用例应该如何?

那里有一些干净的例子吗?

(clean表示不依赖于其他框架或库)

Rob*_*ain 38

JsonSerializer

该示例是序列化a LocalDateTime但可以由所需类型替换.

@Test
public void serialises_LocalDateTime() throws JsonProcessingException, IOException {
    Writer jsonWriter = new StringWriter();
    JsonGenerator jsonGenerator = new JsonFactory().createGenerator(jsonWriter);
    SerializerProvider serializerProvider = new ObjectMapper().getSerializerProvider();
    new LocalDateTimeJsonSerializer().serialize(LocalDateTime.of(2000, Month.JANUARY, 1, 0, 0), jsonGenerator, serializerProvider);
    jsonGenerator.flush();
    assertThat(jsonWriter.toString(), is(equalTo("\"2000-01-01T00:00:00\"")));
}
Run Code Online (Sandbox Code Playgroud)

JsonDeserializer

示例是反序列化a Number但可以用所需类型替换.

    private ObjectMapper mapper;
    private CustomerNumberDeserialiser deserializer;

    @Before
    public void setup() {
        mapper = new ObjectMapper();
        deserializer = new CustomerNumberDeserialiser();
    }

    @Test
    public void floating_point_string_deserialises_to_Double_value() {
        String json = String.format("{\"value\":%s}", "\"1.1\"");
        Number deserialisedNumber = deserialiseNumber(json);
        assertThat(deserialisedNumber, instanceOf(Double.class));
        assertThat(deserialisedNumber, is(equalTo(1.1d)));
    }

    @SneakyThrows({JsonParseException.class, IOException.class})
    private Number deserialiseNumber(String json) {
        InputStream stream = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
        JsonParser parser = mapper.getFactory().createParser(stream);
        DeserializationContext ctxt = mapper.getDeserializationContext();
        parser.nextToken();
        parser.nextToken();
        parser.nextToken();
        return deserializer.deserialize(parser, ctxt);
    }
Run Code Online (Sandbox Code Playgroud)

UPDATE

当升级到jackson 2.9.3时,我将字符串反序列化为数字时收到了NullPointerExceptionin DeserializationContextin isEnabled(MapperFeature feature),因为new ObjectMapper()初始化_confignull.

为了解决这个问题,我使用这个 SO答案来窥探这个final课程DeserializationContext:

DeserializationContext ctxt = spy(mapper.getDeserializationContext());
doReturn(true).when(ctxt).isEnabled(any(MapperFeature.class));
Run Code Online (Sandbox Code Playgroud)

我觉得必须有一个更好的方法,所以如果你有一个,请评论.

  • 对于那些喜欢我的人,想知道什么是`parser.nextToken`在这里重复了三次 - 这意味着我们试图将解析器从json` {value:1.1}`移动到值`1.1`.`parser.nextToken`需要三次,因为订单是START_OBJECT,FIELD_NAME,VALUE_STRING,我们希望在示例中达到VALUE_STRING (3认同)

bon*_*onh 12

其他答案很好地涵盖了序列化。对于反序列化,我还有其他建议。

如果您的域类具有@JsonDeserialize注释,则默认的ObjectMapper将使用反序列化器,而无需显式注册它。

@JsonDeserialize(using=ExampleDeserializer.class)
public class Example {
    private String name;
    private BananaStore bananaStore;

    public Example(String name, BananaStore bananaStore) {
        this.name = name;
        this.bananaStore = bananaStore;
    }

    public String getName() {
        return name;
    }

    public BananaStore getBananaStore() {
        return bananaStore;
    }
}
Run Code Online (Sandbox Code Playgroud)

并且您的单元测试可以变得更短:

public class ExampleDeserializerTest {

    @Test
    public void deserialize() throws IOException {
        String json = "{\"name\":\"joe\",\"bananas\":16}";

        Example example = new ObjectMapper().readValue(json, Example.class);

        assertEquals("joe", example.getName());
        assertEquals(16, example.getBananaStore().getBananaCount());
    }
}
Run Code Online (Sandbox Code Playgroud)


Emi*_*nde 6

解串器可以像这样进行单元测试:

public class CustomFooDeserializerTest {

  private Foo foo;

  @Before
  public void setUp() {
    ObjectMapper objectMapper = new ObjectMapper();
    SimpleModule module = new SimpleModule();
    module.addDeserializer(Foo.class, new CustomFooDeserializer());
    objectMapper.registerModule(module);
    foo = objectMapper.readValue(new File("path/to/file"), Foo.class);
  }

  @Test
  public void shouldSetSomeProperty() {
    assertThat(foo.getSomeProperty(), is("valueOfSomeProperty"));
  }

}    
Run Code Online (Sandbox Code Playgroud)