Spring Boot 1.5.9中如何Mock自定义Jackson反序列化器响应
解决@WebMvcTest中Mock自定义JsonDeserializer的问题
我之前也碰到过完全一样的坑——用@WebMvcTest测试控制器时,自定义的JsonDeserializer总是被直接实例化,Mock根本没生效,最后还抛出了NPE。核心原因确实像你推测的那样:默认情况下,Jackson会直接new你在@JsonDeserializer(using = ...)里指定的类,这个实例不在Spring的ApplicationContext管理范围内,所以Spring的Mock机制(比如@MockBean)根本触达不到它。
不用急着切换到@SpringBootTest(毕竟加载完整上下文会慢很多),这里有两种可行的解决方案:
方案一:把反序列化器转为Spring Bean,让Jackson从容器获取实例
这是更优雅的长期方案,能让反序列化器享受Spring的依赖注入和管理:
- 给你的自定义反序列化器加上
@Component注解,把它变成Spring Bean:
@Component public class MyCustomDeserializer extends JsonDeserializer<YourTargetType> { // 原来的deserialize方法逻辑 }
- 修改实体类上的
@JsonDeserializer注解,改用usingProvider来引用Spring容器中的Bean:
public class YourEntity { @JsonDeserializer(usingProvider = MyDeserializerProvider.class) private YourTargetType yourField; // 内部类实现JsonDeserializerProvider public static class MyDeserializerProvider extends JsonDeserializerProvider<MyCustomDeserializer> { @Autowired private MyCustomDeserializer deserializer; @Override public MyCustomDeserializer getInstance() { return deserializer; } } }
- 现在在
@WebMvcTest测试类里,直接用@MockBean就能Mock这个反序列化器了:
@WebMvcTest(YourController.class) public class YourControllerTest { @MockBean private MyCustomDeserializer customDeserializer; @Autowired private MockMvc mockMvc; @Test public void testController() throws Exception { // Mock deserialize方法的返回值 when(customDeserializer.deserialize(any(JsonParser.class), any(DeserializationContext.class))) .thenReturn(yourMockedObject); // 执行MockMvc请求测试 mockMvc.perform(post("/your-endpoint") .contentType(MediaType.APPLICATION_JSON) .content("{...}")) .andExpect(status().isOk()); } }
方案二:在测试中自定义Jackson的ObjectMapper,替换反序列化器
如果你不想修改现有代码结构,可以在测试类中手动配置ObjectMapper,把Mock的反序列化器注册进去:
@WebMvcTest(YourController.class) public class YourControllerTest { @Autowired private MockMvc mockMvc; // 自定义ObjectMapper,注册Mock的反序列化器 @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); // 创建Mock的反序列化器实例 MyCustomDeserializer mockDeserializer = Mockito.mock(MyCustomDeserializer.class); // Mock返回结果 when(mockDeserializer.deserialize(any(), any())).thenReturn(yourMockedObject); // 把Mock的反序列化器注册到模块中 module.addDeserializer(YourTargetType.class, mockDeserializer); mapper.registerModule(module); return mapper; } // 测试方法... }
这样@WebMvcTest会使用你自定义的ObjectMapper,而不是默认的,从而让请求解析时使用Mock的反序列化器,避免执行原方法体。
为什么原来的方式不生效?
再重申下核心原因:当你用@JsonDeserializer(using = MyCustomDeserializer.class)时,Jackson会在需要反序列化时直接调用new MyCustomDeserializer()创建实例,这个实例完全脱离Spring容器的管理,所以你用@MockBean创建的Mock实例根本不会被用到,自然会执行原方法体导致NPE。
内容的提问来源于stack exchange,提问作者ReservedDeveloper
相关产品推荐
相关产品推荐

