Mockito模拟Optional.get()遇异常,无法Mock Optional类如何解决?
为什么你的写法会报错?
MissingMethodInvocationException异常原因
你写的when(Optional.of(someclass).get()).thenReturn(something)无效,因为Optional.of(someclass)创建的是真实的Optional实例,Mockito只能拦截mock对象的方法调用,无法对真实对象的方法进行存根,所以会抛出这个异常。无法Mock Optional类的原因
Optional是Java的final类,Mockito默认不支持mock final类,这是默认配置限制。
正确的做法:不要Mock Optional,用真实实例包裹Mock对象
Optional是设计用来处理空值的简单容器,完全不需要mock它。直接用真实的Optional实例包裹你的mock对象即可:
示例1:返回包含Mock对象的Optional
@Mock private SomeClass mockSomeClass; // 假设你要让某个服务方法返回Optional<SomeClass> when(yourService.yourMethod()).thenReturn(Optional.of(mockSomeClass)); // 当你调用该方法获取Optional后,调用get()会直接返回mock的mockSomeClass
示例2:返回空Optional(模拟无值场景)
如果需要模拟Optional为空的情况,直接返回Optional.empty()即可,此时调用get()会自动抛出NoSuchElementException,无需额外mock:
when(yourService.yourMethod()).thenReturn(Optional.empty());
(不推荐)如果非要Mock Optional类
如果你确实有特殊需求要mock Optional,需要开启Mockito的inline mock maker:
- 在测试资源目录下创建文件:
src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker - 在文件中写入一行内容:
mock-maker-inline - 之后就可以正常mock Optional了:
@Mock private Optional<SomeClass> mockOptional; when(mockOptional.get()).thenReturn(mockSomeClass);
但再次强调:这完全没必要,Optional是轻量级值对象,用真实实例更简单且符合设计意图。
结合你的测试代码调整
你的测试方法名为shouldAlwaysCreteModelTest,看起来是要验证当findExistingModel返回空时,会调用modelService.create。所以你需要把findExistingModel的返回值改成Optional.empty(),而不是Optional.of(model):
@Test public void shouldAlwaysCreteModelTest() { // 模拟找不到已有模型,返回空Optional when(objectsService.findExistingModel(importDto.getCode(), importDto.getName())).thenReturn(Optional.empty()); when(modelService.create(ToCreateModel.class)).thenReturn(model); final ToCreateModel result = createObjects.retrieveOrCreateModel(importDto); assertNotNull("result should not be null", result); assertEquals("Should create ToCreateModel", model, result); verify(modelService).create(eq(ToCreateModel.class)); }
内容的提问来源于stack exchange,提问作者r17

