私は@JsonDeserializeが付い@Autowiredパラメータと私のエンティティとコンストラクタを使用してインスタンス化されたカスタムデシリアライザに単体テストを記述しようとしています。それはMockMvcは春のサーバーサイドを立ち上げる私の統合テストで正常に動作します。
しかしobjectMapper.readValueは(...)と呼ばれているテストで、パラメータなしでデフォルトコンストラクタを使用してデシリアライザの新しいインスタンスがインスタンス化されます。たとえ
@Bean
public MyDeserializer deserializer(ExternalObject externalObject)
デシリアライザの有線バージョンをインスタンス化し、実際の呼び出しは、まだ空のコンストラクタとコンテキストに渡されるがいっぱいになっていません。
私は手動でデシリアライザインスタンスのインスタンス化とObjectMapperでそれを登録しようとしたが、私は私のエンティティクラスから@JsonDeserializeを削除する場合にのみ動作します(と私は私の@Configurationクラスで同じことをしても、それは私の統合テストを中断します。) -ルックス関連します:これにhttps://github.com/FasterXML/jackson-databind/issues/1300
私はまだ直接(...)deserializer.deserializeを呼び出すデシリアライザの動作をテストすることができますが、このアプローチは、デシリアライザのユニットテストではありませんテストで私のために動作しません...
UPD:以下の作業コード
import com.fasterxml.jackson.annotation.JacksonInject;
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 com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
import com.github.tomakehurst.wiremock.common.Json;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.JsonTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import java.io.IOException;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@JsonTest
@RunWith(SpringRunner.class)
public class JacksonInjectExample {
private static final String JSON = "{\"field1\":\"value1\", \"field2\":123}";
public static class ExternalObject {
@Override
public String toString() {
return "MyExternalObject";
}
}
@JsonDeserialize(using = MyDeserializer.class)
public static class MyEntity {
public String field1;
public String field2;
public String name;
public MyEntity(ExternalObject eo) {
name = eo.toString();
}
@Override
public String toString() {
return name;
}
}
@Component
public static class MyDeserializer extends JsonDeserializer<MyEntity> {
@Autowired
private ExternalObject external;
public MyDeserializer() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
public MyDeserializer(@JacksonInject final ExternalObject external) {
this.external = external;
}
@Override
public MyEntity deserialize(JsonParser p, DeserializationContext ctxt) throws IOException,
JsonProcessingException {
return new MyEntity(external);
}
}
@Configuration
public static class TestConfiguration {
@Bean
public ExternalObject externalObject() {
return new ExternalObject();
}
@Bean
public MyDeserializer deserializer(ExternalObject externalObject) {
return new MyDeserializer(externalObject);
}
}
@Test
public void main() throws IOException {
HandlerInstantiator hi = mock(HandlerInstantiator.class);
MyDeserializer deserializer = new MyDeserializer();
deserializer.external = new ExternalObject();
doReturn(deserializer).when(hi).deserializerInstance(any(), any(), eq(MyDeserializer.class));
final ObjectMapper mapper = Json.getObjectMapper();
mapper.setHandlerInstantiator(hi);
final MyEntity entity = mapper.readValue(JSON, MyEntity.class);
Assert.assertEquals("MyExternalObject", entity.name);
}
}
非常に興味深い質問、それは私がジャクソンデシリアライザにオートワイヤリングが実際に春のアプリケーションでどのように機能するか疑問に思うしました。使用されているジャクソン施設があるように思わHandlerInstantiator
インタフェースされ、にバネで構成されたSpringHandlerInstantiator
実装だけでアプリケーションのコンテキストでクラスを検索します。
だから、理論的には、あなたは、セットアップANができObjectMapper
、あなた自身とあなたのユニットテストでは(嘲笑)をHandlerInstantiator
から準備されたインスタンスを返します、deserializerInstance()
。返すために罰金であると考えられるnull
他の方法またはクラス・パラメータが一致しない場合、これはジャクソンが独自にインスタンスを作成します。
しかし、私は、これはユニットテストのデシリアライゼーション・ロジックには良い方法だとは思わないObjectMapper
セットアップは、実際のアプリケーションの実行中に使用されるものとは必ずしも異なっています。使用JsonTest
アントンの答えで提案されているよう注釈を使用すると、実行時に使用されるのと同じJSONの設定を取得しているとして、よりよい方法でしょう。