You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:40:46