如何对JDBC中的ResultSetExtractor进行单元测试?
如何对JDBC中匿名类实现的ResultSetExtractor进行单元测试?
完全理解你的场景——用匿名类实现ResultSetExtractor确实会让测试时的依赖捕获有点棘手,不过用ArgumentCaptor完全可以搞定,下面我给你详细的步骤和代码示例:
1. 准备测试环境与Mock对象
首先确保你的测试类引入了Mockito相关依赖(如果用Spring Boot的话,spring-boot-starter-test已经包含了),然后Mock掉JdbcTemplate,并把它注入到你的业务类中:
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.sql.ResultSet; import java.sql.SQLException; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) public class YourServiceTest { @Mock private JdbcTemplate jdbcTemplate; @InjectMocks private YourService yourService; // 替换成你的实际业务类 }
2. 定义ArgumentCaptor捕获ResultSetExtractor实例
因为你用的是匿名内部类,我们直接针对ResultSetExtractor<Item>类型定义捕获器:
ArgumentCaptor<ResultSetExtractor<Item>> extractorCaptor = ArgumentCaptor.forClass(ResultSetExtractor.class);
3. 执行目标方法并捕获参数
调用你业务类中包含那段JDBC查询的方法,然后通过verify方法捕获jdbcTemplate.query调用时传入的ResultSetExtractor实例:
@Test void testExtractItemWhenExists() throws SQLException { String itemId = "test-id"; // 调用目标方法 yourService.getItemById(itemId); // 捕获ResultSetExtractor参数 verify(jdbcTemplate).query( anyString(), extractorCaptor.capture(), eq(itemId) ); }
4. 模拟ResultSet行为并验证提取逻辑
现在你已经拿到了ResultSetExtractor实例,接下来MockResultSet对象,模拟不同的查询结果(存在数据/不存在数据),调用extractData方法验证逻辑是否正确:
测试数据存在的场景:
@Test void testExtractItemWhenExists() throws SQLException { String itemId = "test-id"; String expectedName = "test-item"; String expectedDesc = "test-desc"; // Mock ResultSet ResultSet mockRs = mock(ResultSet.class); when(mockRs.next()).thenReturn(true); when(mockRs.getString(1)).thenReturn(expectedName); when(mockRs.getString(2)).thenReturn(expectedDesc); // 调用目标方法并捕获提取器 yourService.getItemById(itemId); verify(jdbcTemplate).query(anyString(), extractorCaptor.capture(), eq(itemId)); // 执行提取逻辑并断言结果 Item result = extractorCaptor.getValue().extractData(mockRs); assertNotNull(result); assertEquals(expectedName, result.getName()); // 替换成你的Item类实际字段 assertEquals(expectedDesc, result.getDescription()); }
测试数据不存在的场景:
@Test void testExtractItemWhenNotExists() throws SQLException { String itemId = "non-exist-id"; // Mock ResultSet,next()返回false ResultSet mockRs = mock(ResultSet.class); when(mockRs.next()).thenReturn(false); // 调用目标方法并捕获提取器 yourService.getItemById(itemId); verify(jdbcTemplate).query(anyString(), extractorCaptor.capture(), eq(itemId)); // 执行提取逻辑并断言返回null Item result = extractorCaptor.getValue().extractData(mockRs); assertNull(result); }
关键注意点
- 确保
verify方法的参数匹配正确:anyString()匹配SQL语句,eq(itemId)匹配参数,这样才能准确捕获到对应的ResultSetExtractor - 模拟
ResultSet时,要覆盖所有在extractData中用到的方法(比如next()、getString()等),避免抛出NullPointerException - 如果你的
extractData方法中处理了SQLException,测试时可以通过doThrow(SQLException.class).when(mockRs).next()来模拟异常场景
内容的提问来源于stack exchange,提问作者Dixon Ivey
相关产品推荐
相关产品推荐

