You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 22:33:01