Java Mockito测试报错:Argument passed to verify is not a Mock如何解决?
解决Mockito测试报错与完善测试用例的思路
你遇到的Argument passed to verify() is of type ExamRepository and is not a mock!错误,根源确实是手动创建ExamRepository实例的那行代码,同时你的测试逻辑也存在一些需要调整的地方,我来一步步帮你梳理:
一、修复Verify报错的核心问题
错误原因拆解
@InjectMocks的作用:这个注解已经会自动帮你创建ExamRepository的真实实例,并把你用@Mock标记的EntityManager注入到实例中,完全不需要你手动new。verify()的限制:这个方法只能用于Mock对象或Spy对象,而你手动new出来的ExamRepository是真实类实例,不是Mockito管理的Mock/Spy,所以会触发报错。- 测试逻辑顺序错误:你现在直接验证
getAllSkeletons执行了一次,但实际上根本没调用这个方法!正确的测试流程应该是:先调用被测方法,再验证依赖行为,最后断言结果。
修正后的基础测试类
public class ExamRepositoryTest { @InjectMocks private ExamRepository examRepository; @Mock private EntityManager entityManager; @Mock private TypedQuery<ExamSkeleton> typedQuery; @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); @Test public void getAllSkeletons_ShouldReturnExpectedList() { // 1. 准备测试数据 List<ExamSkeleton> expectedSkeletons = new ArrayList<>(); expectedSkeletons.add(new ExamSkeleton()); expectedSkeletons.add(new ExamSkeleton()); // 2. Mock依赖的行为 when(entityManager.createQuery( "SELECT NEW ExamSkeleton (s.id, s.filename, s.course, s.visible) FROM ExamSkeleton as s", ExamSkeleton.class )).thenReturn(typedQuery); when(typedQuery.getResultList()).thenReturn(expectedSkeletons); // 3. 调用被测方法 List<ExamSkeleton> actualSkeletons = examRepository.getAllSkeletons(); // 4. 断言返回结果符合预期 assertEquals(expectedSkeletons.size(), actualSkeletons.size()); assertEquals(expectedSkeletons, actualSkeletons); // 5. 验证依赖方法被正确调用 verify(entityManager, times(1)).createQuery( eq("SELECT NEW ExamSkeleton (s.id, s.filename, s.course, s.visible) FROM ExamSkeleton as s"), eq(ExamSkeleton.class) ); verify(typedQuery, times(1)).getResultList(); } }
二、除了方法执行验证,还需要覆盖这些测试场景
针对getAllSkeletons方法,完整的测试需要覆盖正常流程、异常流程、边界场景三类:
1. 异常场景:当createQuery抛出IllegalArgumentException
此时方法应该返回空列表,并且错误日志被正确记录。
@Test public void getAllSkeletons_WhenCreateQueryThrowsException_ShouldReturnEmptyList() { // Mock抛出异常 when(entityManager.createQuery(anyString(), eq(ExamSkeleton.class))) .thenThrow(new IllegalArgumentException("Invalid JPQL statement")); // 调用被测方法 List<ExamSkeleton> result = examRepository.getAllSkeletons(); // 断言返回空列表 assertTrue(result.isEmpty()); // 验证日志被错误级别调用(注:原类中Logger是静态获取的,若要验证日志,需用PowerMockMock静态的LogManager,或者调整类设计让Logger可注入) // 示例PowerMock代码(需引入PowerMock依赖): // PowerMockito.mockStatic(LogManager.class); // Logger mockLogger = mock(Logger.class); // when(LogManager.getLogger(ExamRepository.class)).thenReturn(mockLogger); // verify(mockLogger, times(1)).error(any(IllegalArgumentException.class)); }
2. 边界场景:数据库中无任何ExamSkeleton记录
此时方法应返回空列表而非null,确保代码的空安全。
@Test public void getAllSkeletons_WhenNoRecordsExist_ShouldReturnEmptyList() { when(entityManager.createQuery(anyString(), eq(ExamSkeleton.class))).thenReturn(typedQuery); when(typedQuery.getResultList()).thenReturn(Collections.emptyList()); List<ExamSkeleton> result = examRepository.getAllSkeletons(); assertTrue(result.isEmpty()); verify(typedQuery, times(1)).getResultList(); }
3. 验证JPQL语句的正确性
在正常流程的测试中,我们用eq()匹配完整的JPQL语句,这能有效避免JPQL拼写错误(比如字段名、实体名写错)导致的隐性bug。
关键总结
- 永远不要手动创建
@InjectMocks标记的类实例,让Mockito自动处理依赖注入 verify()的核心作用是验证Mock依赖的交互行为,而非被测类的方法执行(除非被测类是Spy对象)- 测试用例要覆盖所有可能的分支路径,不能只测“正常跑通”的场景
- 测试既要断言返回结果的正确性,也要验证依赖的调用是否符合预期
内容的提问来源于stack exchange,提问作者Bjorn Pijpops
相关产品推荐
相关产品推荐

