我已經爲我的應用程序編寫了自定義的JsonSerializer和JsonDeserializer。 現在我想爲它們編寫一些單元測試。如何對Jackson JsonSerializer和JsonDeserializer進行單元測試
乾淨的測試案例應該如何?
那裏有一些乾淨的例子嗎?
(清潔方法不依賴於其他框架或庫)
我已經爲我的應用程序編寫了自定義的JsonSerializer和JsonDeserializer。 現在我想爲它們編寫一些單元測試。如何對Jackson JsonSerializer和JsonDeserializer進行單元測試
乾淨的測試案例應該如何?
那裏有一些乾淨的例子嗎?
(清潔方法不依賴於其他框架或庫)
我沒有找到任何的例子,但你可以嘗試創建像發電機:
StringWriter stringJson = new StringWriter();
JsonGenerator generator = new JsonFactory().createGenerator(stringJson);
,你可以得到一個SerializerProvider
實例與
new ObjectMapper().getSerializerProvider();
我找到了一種方法來單元測試Deserializers,是相當麻煩弄清楚。看看我的回購https://bitbucket.org/arbeitsgruppedenktmit/de.denktmit.rest.hal
單元測試類是在這裏: de.denktmit.rest.hal/src目錄/測試/ JAVA /德/ denktmit/REST/HAL /傑克遜/ RelationDeserializerTest.java
集成測試,在測試範圍內的解串器可以在這裏找到: de.denktmit.rest.hal/src目錄/測試/ JAVA /德/ denktmit/REST/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));
}
}
希望幫助和問候
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我isEnabled(MapperFeature feature)
deserialising字符串時的數字,因爲new ObjectMapper()
初始化_config
到null
在DeserializationContext
收到NullPointerException
。
要解決這個問題,我用this SO回答窺視DeserializationContext
的final
類:
DeserializationContext ctxt = spy(mapper.getDeserializationContext());
doReturn(true).when(ctxt).isEnabled(any(MapperFeature.class));
我覺得必須有一個更好的辦法,所以請評論,如果你有一個。
文件中讀取JSON對於那些誰喜歡我不知道什麼是'解析器.nextToken'在這裏重複了三次 - 這意味着我們試圖將解析器從json {{value:1.1}'移動到值'1.1'。 'parser.nextToken'需要三次,因爲順序是START_OBJECT,FIELD_NAME,VALUE_STRING,我們希望在示例 – nilesh
@nilesh中達到VALUE_STRING:有沒有辦法避免parser.nextToken重複3次?我有類似的要求,但不想使用parser.nextToken 3次 – kedar
我看了[JsonParser API](http://fasterxml.github.io/jackson-core/javadoc/2.1.0/com/fasterxml/jackson/ core/JsonParser.html?is-external = true)和[JsonParser source](https://github.com/FasterXML/jackson-core/blob/master/src/main/java/com/fasterxml/jackson/core/ JsonParser.java),我不相信有。 –
解串器進行單元測試是這樣的:
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"));
}
}
分號前有一個缺失括號):assertThat(foo.getSomeProperty(),is(「valueOfSomeProperty」);我無法編輯因爲它只有1個字符:-)。 –
的@rule資源文件只是一個幫手,輕鬆地從測試/資源 –