Mockito测试MyBatis DAO抛出InvalidUseOfMatcherException求助
Mockito单元测试异常排查方案
运行测试报错:预期抛出
com.mycompany.exception.ApplicationException,实际抛出org.mockito.exceptions.misusing.InvalidUseofMatcherException
你碰到的InvalidUseOfMatcherException是Mockito框架规则使用错误触发的,并非被测业务代码抛出的异常,自然会出现异常类型不匹配的问题,具体错误点和修复方案如下:
核心错误点
- 测试方法不符合JUnit规范:
@Test修饰的方法不能声明入参,也不能有返回值,你当前写的测试方法返回List<EcommProfile>、带String ssoId入参,本身就不符合测试方法的定义要求。 - 匹配器使用位置错误:Mockito的参数匹配器(如
Mockito.eq())仅允许在打桩(when/verify代码块)的参数位置使用,你在实际调用被测方法时传入了Mockito.eq("12345")作为参数,这是触发匹配器异常的直接原因——真实方法调用直接传实际参数即可,不能用匹配器。 - 异常断言API使用错误:
Assertions.assertTrue是用来断言布尔值结果的,根本不支持异常断言场景。JUnit5中要校验方法抛出指定异常,需要使用Assertions.assertThrows方法。 - 命名拼写不一致:你测试代码中调用的方法名
getEmployeeProfileByssoId、SqlSession相关类名拼写和被测代码中的定义存在出入,会直接导致方法调用不匹配。 - 打桩逻辑顺序不合理:需要先打桩外层依赖
sqlSessionFactory.openEcomSession()的返回值,再打桩内层sqlSession.selectList的行为,避免mock对象未正确关联的问题。 - 缺少Mockito启动注解:未添加
@ExtendWith(MockitoExtension.class)(JUnit5)或@RunWith(MockitoJUnitRunner.class)(JUnit4)注解的话,@Mock和@InjectMocks标注的对象不会被初始化,会出现空指针问题。
修正后可运行的测试代码
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import java.util.List; @ExtendWith(MockitoExtension.class) public class EcommDaoTest { @Mock SqlSessionFactory sqlSessionFactory; // 注意类名要和被测代码中import的Sqlsession完全一致,注意大小写 @Mock Sqlsession sqlsession; // 类名要和实际被测Dao实现类名完全一致 @InjectMocks EcommDaoimpl ecommDao; @Test public void getEmployeePorfilebySsoIdTestException() { // 先打桩外层会话工厂返回mock的sqlsession Mockito.when(sqlSessionFactory.openEcomSession()).thenReturn(sqlsession); // 打桩selectList调用时抛出指定异常 Mockito.when(sqlsession.selectList(Mockito.eq("org.mybatis.ecommprofile"), Mockito.eq("12345"))) .thenThrow(ApplicationException.class); // 用assertThrows断言异常,调用被测方法时直接传真实参数,不要用匹配器 Assertions.assertThrows(ApplicationException.class, () -> ecommDao.getEmployeePorfilebySsoId("12345")); } }
额外注意事项
如果你的ApplicationException是受检异常(非RuntimeException子类),直接用thenThrow(ApplicationException.class)会报错,因为MyBatis的selectList方法本身没有声明抛出该受检异常,这种场景需要先确认业务代码里的异常转换逻辑是否符合预期。
内容的提问来源于stack exchange,提问作者man123
相关产品推荐
相关产品推荐

