JUnit Mockito单元测试ObjectMapper.writeValueAsString返回null
@Mock注解生成的是Mockito代理的空实现对象,不会执行ObjectMapper原生的序列化逻辑。所有未手动配置桩(Stub)的方法,调用时会直接返回对应返回类型的默认值:writeValueAsString方法返回值是String类型,默认值就是null,这就是你拿到null的直接原因。
补充说明:从现象判断你的Mock对象已经成功注入到被测服务了——如果注入失败,调用objectMapper.writeValueAsString()时会直接抛空指针异常,不会等到拿返回值才发现异常。另外你代码里用的MockitoAnnotations.initMocks(this)已经被标记废弃,新版本Mockito推荐使用MockitoAnnotations.openMocks(this)替代。
根据测试场景选一种方案即可:
方案1:不需要Mock ObjectMapper时直接用真实实例(最常用,适合绝大多数单元测试场景)
ObjectMapper本身是无外部依赖的序列化工具类,完全不需要Mock,直接实例化真实对象注入被测类即可,原生序列化逻辑会正常执行:// 不要加@Mock注解,直接初始化真实的ObjectMapper private ObjectMapper objectMapper = new ObjectMapper(); @InjectMocks private YourAckService ackService; // 替换成你自己的被测服务类 @BeforeEach public void setUp() { MockitoAnnotations.openMocks(this); }这种方式下
writeValueAsString会正常执行序列化逻辑,返回你预期的{"ID":"123"}字符串。方案2:必须Mock ObjectMapper时手动配置方法桩
如果你需要验证ObjectMapper的调用次数、入参是否符合预期,必须给Mock对象配置桩规则,明确指定方法调用的返回值:@Mock private ObjectMapper objectMapper; @InjectMocks private YourAckService ackService; @BeforeEach public void setUp() throws JsonProcessingException { MockitoAnnotations.openMocks(this); // 配置桩:传入任意Map调用writeValueAsString时,返回指定的JSON串 when(objectMapper.writeValueAsString(anyMap())).thenReturn("{\"ID\":\"123\"}"); } @Test public void testAckSend() throws JsonProcessingException { // 执行被测业务逻辑 ackService.sendAck(); // 可选:验证方法调用符合预期 verify(objectMapper, times(1)).writeValueAsString(argThat(map -> "123".equals(map.get("ID")))); }方案3:Spring集成测试场景直接注入容器真实Bean
如果你写的是Spring层集成测试,不需要手动Mock,直接用@SpringBootTest加载应用上下文,把项目中配置的真实ObjectMapper Bean注入即可,不会出现返回null的问题。
内容的提问来源于stack exchange,提问作者Jikya

