Mockito verify方法未触发:如何验证ObjectMapper的readValue调用?
解决Mockito验证ObjectMapper.readValue调用失败的问题
你碰到的这个问题很典型——你在测试里mock的ObjectMapper,根本没被MyService用上。
看一下你的MyService代码:里面的objectMapper是直接用new ObjectMapper()创建的,这意味着MyService运行时用的是它自己实例化的ObjectMapper,和你测试类里mock出来的那个完全是两个独立的对象。Mockito当然捕获不到它的调用了,因为调用根本没发生在你mock的实例上。
给你两种解决方案,优先选第一种:
方案1:用构造函数注入ObjectMapper(推荐)
这是最符合依赖注入原则的做法,也让代码的依赖关系更清晰,测试起来更方便。
首先修改你的MyService,把ObjectMapper通过构造函数传入:
@Service public class MyService { public static final Logger logger = LoggerFactory.getLogger(MyService.class); private final ObjectMapper objectMapper; // 构造函数注入ObjectMapper public MyService(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } public void logData(String personData) throws IOException{ Person person = objectMapper.readValue(personData, Person.class); logger.info("log person: {}, {}", person.getName(), person.getAge()); } }
然后调整测试类,把mock的ObjectMapper通过构造函数传给MyService:
@RunWith(MockitoJUnitRunner.class) public class MyServiceTest { public static final Logger logger = LoggerFactory.getLogger(MyServiceTest.class); @Mock ObjectMapper objectMapper; // 把mock的ObjectMapper注入到MyService实例中 MyService myService = new MyService(objectMapper); @Test public void verifyCallToReadValue() throws IOException{ String personData = "{\"Name\":\"debieA\",\"Age\":\"31\"}"; // 提前指定mock的readValue方法返回值,避免后续调用logger时出现空指针 when(objectMapper.readValue(eq(personData), eq(Person.class))) .thenReturn(new Person("debieA", 31)); myService.logData(personData); // 现在就能正确捕获到调用了 verify(objectMapper, times(1)).readValue(personData, Person.class); } }
方案2:用反射注入(不推荐,仅当无法修改MyService时使用)
如果因为某些原因你不能修改MyService的构造函数,可以用反射强行替换它内部的objectMapper字段,但这种方式属于hack手段,会破坏封装,后续代码变更容易导致测试失败。
修改测试类如下:
@RunWith(MockitoJUnitRunner.class) public class MyServiceTest { public static final Logger logger = LoggerFactory.getLogger(MyServiceTest.class); @Mock ObjectMapper objectMapper; MyService myService = new MyService(); @Test public void verifyCallToReadValue() throws IOException, NoSuchFieldException, IllegalAccessException{ // 通过反射获取MyService的objectMapper字段 Field objectMapperField = MyService.class.getDeclaredField("objectMapper"); // 允许访问私有字段 objectMapperField.setAccessible(true); // 把字段值替换成我们mock的实例 objectMapperField.set(myService, objectMapper); String personData = "{\"Name\":\"debieA\",\"Age\":\"31\"}"; when(objectMapper.readValue(eq(personData), eq(Person.class))) .thenReturn(new Person("debieA", 31)); myService.logData(personData); verify(objectMapper, times(1)).readValue(personData, Person.class); } }
总结一下,优先用构造函数注入的方式,它不仅能解决你的测试问题,还能让代码的可维护性更好。
内容的提问来源于stack exchange,提问作者BlueStar
相关产品推荐
相关产品推荐

