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

如何对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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:33:09