Mockito报错:findById()无法返回Boolean,需返回Optional的问题排查
问题分析与解决
错误根源
你遇到的报错核心原因是:试图用Mockito存根真实对象的方法。你的actorService是通过@InjectMocks创建的真实业务类实例,而非Mock对象。当你执行when(actorService.actorExists(actorId)).thenReturn(true)时,Mockito会触发真实的actorExists方法执行,内部检测到方法调用链中存在返回值类型不匹配的冲突(错误提示里的findById()应该返回Optional却被错误关联到Boolean类型的返回逻辑)。
另外,这行存根代码本身完全多余:你已经mock了creativesRepository.findById(actorId)返回Optional.of(actor),真实的actorService.actorExists方法会基于这个mock结果自然返回true,根本不需要额外存根。
解决方案
方案一:移除多余的存根代码(推荐)
直接删除when(actorService.actorExists(actorId)).thenReturn(true)这行代码即可。修改后的测试类如下:
@RunWith(MockitoJUnitRunner.class) public class MovieServiceTest { @Mock private MovieRepository movieRepository; @Mock ActorRepository creativesRepository; @InjectMocks private MovieService movieService; @InjectMocks private ActorService actorService; // 注意:@RunWith(MockitoJUnitRunner.class)已完成mock初始化,无需再调用openMocks // 可删除@BeforeEach方法,或保留时去掉openMocks调用 @Test public void testDeleteActorNotInMovie() throws CreativesDeletionException, CreativesNotFoundException { Long actorId = 1L; Actor actor = new Actor(); actor.setId(actorId); when(creativesRepository.findById(actorId)).thenReturn(Optional.of(actor)); // 此时调用actorService.actorExists(actorId)会自然返回true,可直接用于后续测试逻辑 } }
方案二:将actorService改为Spy对象(仅需存根真实对象方法时使用)
如果确实需要跳过actorService的真实逻辑、直接存根方法返回值,可以将actorService声明为Spy对象,Mockito允许对Spy对象的部分方法进行存根:
@RunWith(MockitoJUnitRunner.class) public class MovieServiceTest { @Mock private MovieRepository movieRepository; @Mock ActorRepository creativesRepository; @InjectMocks private MovieService movieService; @Spy // 添加@Spy注解 @InjectMocks private ActorService actorService; @Test public void testDeleteActorNotInMovie() throws CreativesDeletionException, CreativesNotFoundException { Long actorId = 1L; when(actorService.actorExists(actorId)).thenReturn(true); // 后续测试逻辑 } }
额外优化点
测试类中@RunWith(MockitoJUnitRunner.class)和MockitoAnnotations.openMocks(this)功能重复,二者选其一即可:
- 保留
@RunWith(MockitoJUnitRunner.class)的话,删除@BeforeEach中的MockitoAnnotations.openMocks(this); - 若使用JUnit 5,推荐替换为
@ExtendWith(MockitoExtension.class),无需@RunWith和openMocks调用。
内容的提问来源于stack exchange,提问作者WowBow
相关产品推荐
相关产品推荐

