Mockito测试中返回Optional.empty而非指定对象的问题排查
Mockito测试中findById返回null的解决办法
核心问题分析
你的测试代码存在两个关键冲突点:
- JUnit4环境下混用了JUnit5的注解(
@TestInstance、@BeforeEach),导致测试生命周期异常 - 重复初始化Mock:
@RunWith(MockitoJUnitRunner.class)已经会自动处理@Mock/@InjectMocks的初始化,手动调用MockitoAnnotations.openMocks(this)会重置Stub配置
修复方案一:标准JUnit4+Mockito写法
移除JUnit5注解,删除重复初始化代码,用JUnit4原生的@Before替代@BeforeEach:
@RunWith(MockitoJUnitRunner.class) public class TaskServiceTestWithoutSpring { @Mock private TaskRepository taskRepository; @InjectMocks private TaskService taskService; // 不需要@Spy,除非你要监控服务自身方法 @Before // JUnit4的前置方法注解 public void init(){ Task task = new Task(); task.setId(4); task.setStatus(StatusEnum.IN_PROGRESS); task.setDescription("amazing task"); // 常规Stub写法,两种方式都可用 when(taskRepository.findById(anyInt())).thenReturn(Optional.of(task)); // doReturn(Optional.of(task)).when(taskRepository).findById(anyInt()); } // 必须添加实际测试方法 @Test public void getTaskById_ShouldReturnExistingTask() { Task result = taskService.getTaskById(4); assertNotNull(result); assertEquals("amazing task", result.getDescription()); // 验证仓库方法被调用 verify(taskRepository).findById(4); } }
修复方案二:如果需要Spy TaskService
如果你确实需要监控TaskService自身的方法(比如验证内部调用、Stub服务方法),要显式创建服务实例再包装Spy:
@RunWith(MockitoJUnitRunner.class) public class TaskServiceTestWithoutSpring { @Mock private TaskRepository taskRepository; private TaskService spyTaskService; @Before public void init(){ // 手动创建服务实例并注入Mock仓库 TaskService taskService = new TaskService(taskRepository); // 包装为Spy代理 spyTaskService = Mockito.spy(taskService); Task task = new Task(); task.setId(4); task.setStatus(StatusEnum.IN_PROGRESS); task.setDescription("amazing task"); when(taskRepository.findById(anyInt())).thenReturn(Optional.of(task)); } @Test public void getTaskById_ShouldReturnTask() { Task result = spyTaskService.getTaskById(4); assertNotNull(result); } }
关键注意事项
- 确保TaskService有可访问的构造函数接收TaskRepository(比如
public TaskService(TaskRepository taskRepository)),否则@InjectMocks无法完成注入 - JUnit4中不要使用JUnit5的注解,两者生命周期逻辑不兼容
@RunWith(MockitoJUnitRunner.class)会自动处理所有Mock初始化,禁止重复调用MockitoAnnotations.openMocks(this),否则会清空已配置的Stub
内容的提问来源于stack exchange,提问作者Tommy
相关产品推荐
相关产品推荐

