使用Mockito带参数抛出SQLException时无法被正确识别是什么原因?
问题根本原因
测试代码中直接Mock Dao层方法抛出原始SQLException,跳过了Dao层本身的异常转换逻辑,是该问题的核心诱因。
两种运行流程差异
- 线上正常运行流程:Dao层
insertUser方法内部会捕获SQLException,当错误码为1062时会转换为MySQLEXContainer.MySQLDBNotUniqueException再向外抛出,Service层捕获到该自定义异常后会匹配第二个catch块,抛出符合预期的ApplicationCanChangeException。 - 测试Mock流程:通过Mockito指定
userDao.insertUser直接抛出原始SQLException,没有执行Dao层内部的异常转换代码,Service层的第一个catch块直接匹配到SQLException,因此抛出了ApplicationCanNotChangeException,和测试预期不符。
修复方案
修改测试代码中Mock抛出的异常类型,改为Dao层转换后的自定义异常即可:
@Test void insertUserNotUniqueException() throws SQLException, MySQLEXContainer.MySQLDBExecutionException, MySQLEXContainer.MySQLDBLargeDataException, MySQLEXContainer.MySQLDBNotUniqueException, ApplicationEXContainer.ApplicationCanNotChangeException, ApplicationEXContainer.ApplicationCanChangeException { User user = new User(); user.setLogin("testLogin"); user.setUserEmail("test@example.com"); // 改为抛出DAO转换后的自定义异常 when(userDao.insertUser(any(Connection.class),any(User.class))).thenThrow(new MySQLEXContainer.MySQLDBNotUniqueException(String.format("Your login : %s or Email %s already exists", user.getLogin(), user.getUserEmail()), new SQLException())); Throwable thrown = assertThrows(ApplicationEXContainer.ApplicationCanChangeException.class,()->taxiServiceUser.insertUser(user)); assertEquals("Your login : testLogin or Email test@example.com already exists",thrown.getMessage()); }
如果需要验证Dao层的异常转换逻辑,建议单独编写Dao层单元测试,不需要耦合在Service层的测试逻辑中。
内容的提问来源于stack exchange,提问作者DozezQuest
相关产品推荐
相关产品推荐

