如何使用Mockito为含RowMapper的JdbcTemplate逻辑编写JUnit测试用例?
用Mockito编写该JdbcTemplate查询逻辑的JUnit测试方法
核心思路
不需要连接真实数据库,只需要模拟JdbcTemplate的调用行为,同时通过参数捕获器验证匿名RowMapper的字段映射逻辑是否符合预期即可。
前置依赖
首先需要引入JUnit、Mockito、spring-jdbc相关的测试依赖,Maven配置示例如下:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>4.11.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>4.11.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.9.2</version> <scope>test</scope> </dependency>
如果使用JUnit4,只需替换对应JUnit版本依赖,核心测试逻辑基本一致。
完整测试用例代码
假设你的查询逻辑封装在EmployeeDao类的queryAllEmployee方法中,测试代码如下:
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) public class EmployeeDaoTest { // 模拟JdbcTemplate实例,不会发起真实数据库请求 @Mock private JdbcTemplate jdbcTemplate; // 注入模拟的JdbcTemplate到待测试的Dao类 @InjectMocks private EmployeeDao employeeDao; // 定义参数捕获器,用来捕获代码中的匿名RowMapper实例 @Captor private ArgumentCaptor<RowMapper<Employee>> rowMapperCaptor; @Test public void testQueryAllEmployee() throws SQLException { // 1. 预设查询返回的模拟结果 Employee mockEmployee = new Employee(); mockEmployee.setId("1001"); mockEmployee.setName("张三"); List<Employee> expectedList = List.of(mockEmployee); // 2. 定义JdbcTemplate调用的模拟规则,同时匹配SQL语句 when(jdbcTemplate.query(eq("select * from employee"), any(RowMapper.class))) .thenReturn(expectedList); // 3. 调用待测试的业务方法 List<Employee> actualList = employeeDao.queryAllEmployee(); // 4. 校验返回结果是否符合预期 assertEquals(1, actualList.size()); assertEquals("1001", actualList.get(0).getId()); assertEquals("张三", actualList.get(0).getName()); // ---- 额外校验匿名RowMapper的映射逻辑是否正确 ---- // 捕获调用时传入的匿名RowMapper实例 when(jdbcTemplate.query(eq("select * from employee"), rowMapperCaptor.capture())) .thenReturn(expectedList); employeeDao.queryAllEmployee(); RowMapper<Employee> mapper = rowMapperCaptor.getValue(); // 模拟ResultSet对象,构造测试用的字段值 ResultSet mockRs = mock(ResultSet.class); when(mockRs.getString("ID")).thenReturn("2002"); when(mockRs.getString("NAME")).thenReturn("李四"); // 手动调用mapRow方法校验映射结果 Employee mappedEmp = mapper.mapRow(mockRs, 1); assertEquals("2002", mappedEmp.getId()); assertEquals("李四", mappedEmp.getName()); } }
关键逻辑说明
- 用
eq匹配器校验执行的SQL语句是否和预期一致,可提前发现SQL拼写错误 - 通过
ArgumentCaptor捕获匿名RowMapper,不需要将RowMapper抽取为单独的公共类即可测试内部映射逻辑 - 所有数据库相关对象都是模拟生成,测试执行速度快,不依赖环境可用性
内容的提问来源于stack exchange,提问作者Vinutha
相关产品推荐
相关产品推荐

