2014-02-14 4 views
17

Я написал пользовательский JsonSerializer и JsonDeserializer для своего приложения. Теперь я хочу написать для них некоторые модульные тесты.Как модульный тест Jackson JsonSerializer и JsonDeserializer

Как должен выглядеть чистый тестовый корпус?

Есть ли там чистые примеры?

(чистые средства без зависимостей для других структур или библиотек)

ответ

1

не найти ни одного примера, но вы можете попробовать создать генератор, как:

StringWriter stringJson = new StringWriter(); 
JsonGenerator generator = new JsonFactory().createGenerator(stringJson); 

и вы можете получить SerializerProvider экземпляр с

new ObjectMapper().getSerializerProvider(); 
2

Я нашел способ модульного тестирования Deserializers, было довольно сложно разобраться. Посмотрите на мою репо https://bitbucket.org/arbeitsgruppedenktmit/de.denktmit.rest.hal

Блок тестового класса здесь: de.denktmit.rest.hal/SRC/тест/Java/де/denktmit/отдых/гал/джексон/RelationDeserializerTest.java

интеграционный тест, для тестирования десериализатор в контексте можно найти здесь: de.denktmit.rest.hal/SRC/тест/Java/де/denktmit/отдых/HAL/OrderResourceIntegrationTest.java

правку из-за комментарии Базовый класс для настройки преобразователя для простого модульного тестирования

public abstract class AbstractJackson2MarshallingTest { 

    protected ObjectMapper mapper; 

    @Before 
    public void setUp() { 
     mapper = new ObjectMapper(); 
     mapper.enable(SerializationFeature.INDENT_OUTPUT); 
    } 

    protected String write(Object object) throws Exception { 
     Writer writer = new StringWriter(); 
     mapper.writeValue(writer, object); 
     return writer.toString(); 
    } 

    protected <T> T read(String source, Class<T> targetType) throws Exception { 
     return mapper.readValue(source, targetType); 
    } 

    protected String getPackagePath() { 
     return "/" + this.getClass().getPackage().getName().replace('.', '/'); 
    } 
} 

Тест класс, содержащий блок тестирует

public class RelationDeserializerTest extends AbstractJackson2MarshallingIntegrationTest { 

    @Rule public ResourceFile resourceFile = new ResourceFile(getPackagePath() + "/single_valued_relation.json"); 
    @Rule public ResourceFile resourceFile2 = new ResourceFile(getPackagePath() + "/multi_valued_relation.json"); 

    private RelationDeserializer deserializer = new RelationDeserializer(); 

    @Test 
    public void testDeserializeSingleValuedRelation() throws IOException { 
     resourceFile = new ResourceFile(getPackagePath() + "/single_valued_relation.json"); 
     JsonParser parser = mapper.getFactory().createParser(resourceFile.getContent()); 
     DeserializationContext ctxt = mapper.getDeserializationContext(); 
     SingleValuedRelation rel = (SingleValuedRelation) deserializer.deserialize(parser, ctxt); 
     assertEquals(rel.getName(), "invoiceAddress"); 
     assertEquals("invoiceAddressURL", rel.getLink().getHref()); 
     assertEquals("linkName", rel.getLink().getName()); 
     assertEquals("de", rel.getLink().getHreflang()); 
     assertNull(parser.nextToken()); 
    } 

    @Test 
    public void testDeserializeMultiValuedRelation() throws IOException { 
     resourceFile = new ResourceFile(getPackagePath() + "/multi_valued_relation.json"); 
     JsonParser parser = mapper.getFactory().createParser(resourceFile.getContent()); 
     DeserializationContext ctxt = mapper.getDeserializationContext(); 
     MultiValuedRelation rel = (MultiValuedRelation) deserializer.deserialize(parser, ctxt); 
     assertEquals(rel.getName(), "images"); 
     Iterator<Link> linkIterator = rel.getLinks().iterator(); 
     Link link = linkIterator.next(); 
     assertEquals("imageUrl1", link.getHref()); 
     link = linkIterator.next(); 
     assertEquals("imageUrl2", link.getHref()); 
     assertNull(parser.nextToken()); 
    } 

} 

Класс испытываемого

public class RelationDeserializer extends StdDeserializer<Relation> { 

    public RelationDeserializer() { 
     super(Relation.class); 
    } 

    @Override 
    public Relation deserialize(JsonParser p, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException { 
     if (p.getCurrentToken() == null && p.nextToken() == null) { 
      String msg = getClass().getCanonicalName() 
        + ": Can not deserialize without token"; 
      throw new IOException(msg); 
     } 
     if (p.getCurrentToken() != JsonToken.START_OBJECT 
       && p.getCurrentToken() != JsonToken.START_ARRAY) { 
      String msg = getClass().getCanonicalName() 
        + ": Expected data to start with an Relation object or an array of Relation objects"; 
      throw new IOException(msg); 
     } 
     if (p.nextToken() != JsonToken.FIELD_NAME) { 
      String msg = getClass().getCanonicalName() 
        + ": Expected relation to be started by a field name"; 
      throw new IOException(msg); 
     } 
     String relationName = p.getText(); 
     JsonToken tok = p.nextToken(); 
     Relation rel; 
     switch (tok) { 
     case START_ARRAY: 
      rel = createMultiValuedRelation(relationName, p); 
      break; 
     case START_OBJECT: 
      rel = createSingleValuedRelation(relationName, p); 
      break; 
     default: 
      String msg = getClass().getCanonicalName() + "Expected relation content is a single link or array of links"; 
      throw new IOException(msg); 
     } 
     p.nextToken(); 
     return rel; 
    } 

    private Relation createMultiValuedRelation(String relationName, JsonParser p) 
      throws JsonParseException, IOException { 
     List<Link> links = new ArrayList<Link>(); 
     if (p.nextToken() == JsonToken.START_OBJECT) { 
      Iterator<DefaultLink> linkIterator = p.readValuesAs(DefaultLink.class); 
      while (linkIterator.hasNext()) { 
       links.add(linkIterator.next()); 
      } 
     } 
     if (p.getCurrentToken() != JsonToken.END_ARRAY) { 
      String msg = getClass().getCanonicalName() + "Expected relation content is a single link or (possibly empty) array of links"; 
      throw new IOException(msg); 
     } 
     return RelationFactory.createRelation(relationName, links); 
    } 

    private Relation createSingleValuedRelation(String relationName, 
      JsonParser p) throws JsonParseException, IOException { 
     return RelationFactory.createRelation(relationName, p.readValueAs(DefaultLink.class)); 
    } 


} 

Надежда, что помогает и наилучшими пожеланиями

+0

Файл ресурсов @Rule только помощник, легко читать JSON из файла в тесте/ресурсах –

21

JsonSerializer

Пример: сериализация 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\""))); 
} 

JsonDeserializer

Этот пример deserialising в 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); 
    } 

UPDATE

При обновлении Джексон 2.9.3 я получил NullPointerException в DeserializationContext в isEnabled(MapperFeature feature) когда deserialising строк в число, потому что new ObjectMapper() инициализирует _config к null.

Чтобы обойти эту проблему, я использовал this SO ответ шпионить за final класса DeserializationContext:

DeserializationContext ctxt = spy(mapper.getDeserializationContext()); 
doReturn(true).when(ctxt).isEnabled(any(MapperFeature.class)); 

Я чувствую, что должен быть лучший способ, поэтому, пожалуйста, комментарий, если у вас есть.

+1

Для тех, кто любит меня, интересно, что это 'парсер .nextToken' повторяется три раза здесь. Что это значит, мы пытаемся переместить парсер в значение '1.1' из json' {value: 1.1} '. 'parser.nextToken' требуется три раза, потому что заказ START_OBJECT, FIELD_NAME, VALUE_STRING и мы хотим достичь VALUE_STRING в примере – nilesh

+0

@nilesh: Есть ли способ избежать повторения parser.nextToken 3 раза? У меня есть аналогичное требование, но не хочу использовать parser.nextToken 3 раза – kedar

+0

Я посмотрел на [JsonParser API] (http://fasterxml.github.io/jackson-core/javadoc/2.1.0/com/fasterxml/jackson/ core/JsonParser.html? is-external = true) и [источник JsonParser] (https://github.com/FasterXML/jackson-core/blob/master/src/main/java/com/fasterxml/jackson/core/ JsonParser.java), и я не верю, что есть. –

1

десериализатор может быть протестирован, как это:

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")); 
    } 

}  
+0

В конце строки перед точкой с запятой отсутствует: assertThat (foo.getSomeProperty(), is ("valueOfSomeProperty"); я не могу редактировать так как это всего лишь 1 символ :-). –

Смежные вопросы