如何用Mockito Mock链式调用Object.getMap().get(key)及Bean类类似场景?
在Mockito中处理链式调用(比如object.getMap().get(key)这种嵌套调用),核心是分层Mock每一步返回的对象,不能直接跳过中间层去Mock最内层的方法。我来帮你拆解正确的实现方式,以及分析你之前报错的原因:
一、正确实现两种场景的Mock
场景1:object.getMap().get("String_Key_to_return_Object")
假设getMap()返回的是标准的java.util.Map<String, TargetObject>,步骤如下:
- Mock中间的Map对象
- 让外层对象的
getMap()返回这个Mock的Map - 最后Mock Map的
get()方法返回目标对象
代码示例:
// 1. 准备目标对象(你要返回的Object) TargetObject targetObj = new TargetObject(); // 2. Mock Map对象 Map<String, TargetObject> mockMap = mock(Map.class); // 3. Mock外层对象(假设是YourObject类型) YourObject mockObject = mock(YourObject.class); // 4. 设置外层对象的getMap()返回Mock的Map when(mockObject.getMap()).thenReturn(mockMap); // 5. 设置Mock Map的get()方法返回目标对象 when(mockMap.get("String_Key_to_return_Object")).thenReturn(targetObj);
场景2:ObjectOfBeanClass.getMapObject().get("String_Key_To_Return_Object")
如果getMapObject()返回的是自定义的MapObject类(而非标准Map),思路完全一致:
// 1. 准备目标对象 TargetObject targetObj = new TargetObject(); // 2. Mock自定义的MapObject MapObject mockMapObject = mock(MapObject.class); // 3. Mock你的Bean对象 BeanClass mockBean = mock(BeanClass.class); // 4. 设置Bean的getMapObject()返回Mock的MapObject when(mockBean.getMapObject()).thenReturn(mockMapObject); // 5. 设置Mock MapObject的get()方法返回目标对象 when(mockMapObject.get("String_Key_To_Return_Object")).thenReturn(targetObj);
如果你的ObjectOfBeanClass是真实对象(而非完全Mock的对象),需要用spy来部分Mock:
// 1. 真实Bean对象 BeanClass realBean = new BeanClass(); // 2. 创建spy包装真实对象 BeanClass spyBean = spy(realBean); // 3. Mock MapObject MapObject mockMapObject = mock(MapObject.class); // 4. 用doReturn指定spyBean的getMapObject()返回Mock对象(避免调用真实方法) doReturn(mockMapObject).when(spyBean).getMapObject(); // 5. Mock get()方法 when(mockMapObject.get("String_Key_To_Return_Object")).thenReturn(targetObj);
二、分析你之前的报错原因
错误1:when(ObjectOfBeanClass.getMapObject().get("...")).thenReturn(Object);
当你直接写这段代码时,如果ObjectOfBeanClass是真实对象,getMapObject()会调用真实方法,返回的可能是null或者未初始化的MapObject,Mockito无法拦截这个链式调用——它需要先MockgetMapObject()返回的中间对象,才能继续Mock内层的get()方法。
如果ObjectOfBeanClass是Mock对象,但你没有先设置getMapObject()的返回值,那么它默认返回null,调用get()时自然会抛出空指针或类型不匹配的异常。
错误2:doReturn(Object).when(ObjectOfBeanClass.getMapObject()).thenReturn(Object);
这段代码的语法完全错误!Mockito的doReturn正确用法是:
doReturn(要返回的值).when(Mock/Spy对象).方法名(参数);
你在when()里传入的是ObjectOfBeanClass.getMapObject()的调用结果(而非Mock对象),还额外加了thenReturn,导致Stubbing流程未完成,所以抛出UnfinishedStubbingException。
核心总结
处理链式调用的关键是从外到内逐层Mock:先Mock最外层对象,设置它返回中间层的Mock对象,再Mock中间层对象返回最终目标值,不能一步到位跳过中间层。
内容的提问来源于stack exchange,提问作者mubarak khan

