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

如何用JUnit测试基于JdbcPagingItemReaderBuilder的Spring Batch读取器

问题解决:Spring Batch JdbcPagingItemReaderBuilder测试时无法确定PagingQueryProvider类型

问题根源

你遇到的异常是因为JdbcPagingItemReaderBuilder在构建读取器时,会尝试从DataSource获取连接,通过数据库元数据自动推断对应的分页查询提供者(比如MySQL/Oracle的实现类)。但你用Mockito Mock的DataSource默认返回null连接,导致框架无法完成类型推断,从而抛出异常。另外,你的读取器代码里selectClause存在拼写错误(SELET应为SELECT),后续运行也会触发SQL语法错误,建议一并修正。

解决方案

方案1:显式指定分页查询提供者(推荐单元测试用)

直接指定对应数据库的PagingQueryProvider实现类,跳过框架自动推断逻辑,无需依赖数据库连接。以MySQL为例:

@Configuration
public class RelatorioReader {

    @Bean("relatorioreader")
    @StepScope
    public ItemReader<Relatorio> relatorioItemReader(
        @Qualifier("dataSource") DataSource dataSource,
        @Value("#{jobParameters[dateParam]}") String dateParam) {

        // 显式创建对应数据库的分页查询提供者
        MySqlPagingQueryProvider queryProvider = new MySqlPagingQueryProvider();
        queryProvider.setSelectClause("SELECT *"); // 修正拼写错误
        queryProvider.setFromClause("FROM myTable");
        queryProvider.setWhereClause("WHERE date = :dateParam");
        queryProvider.setSortKeys(Collections.singletonMap("ID", Order.ASCENDING));

        return new JdbcPagingItemReaderBuilder<Relatorio>()
                    .name("relatorioDiario")
                    .dataSource(dataSource)
                    .queryProvider(queryProvider) // 设置显式的查询提供者
                    .parameterValues(Collections.singletonMap("dateParam", dateParam))
                    .rowMapper(new RelatorioMapper())
                    .build();
    }
}

方案2:Mock数据库连接及元数据

在测试中模拟DataSource的getConnection()方法,返回能提供数据库类型信息的Mock对象,让框架可以完成自动推断:

@ExtendWith(MockitoExtension.class)
public class RelatorioReaderTest {

    @InjectMocks
    RelatorioReader reader;

    @Mock
    DataSource dataSource;
    @Mock
    Connection connection;
    @Mock
    DatabaseMetaData databaseMetaData;

    @Test
    public void test_itemReader() throws SQLException {
        // 模拟获取连接
        when(dataSource.getConnection()).thenReturn(connection);
        // 模拟数据库产品名称,根据实际数据库调整(比如"Oracle"、"PostgreSQL")
        when(databaseMetaData.getDatabaseProductName()).thenReturn("MySQL");
        when(connection.getMetaData()).thenReturn(databaseMetaData);

        ItemReader<Relatorio> itemReader = reader.relatorioItemReader(dataSource, "2023-02-16");

        assertNotNull(itemReader);
    }
}

方案3:使用嵌入式数据库做集成测试

如果需要更贴近真实场景的测试,可以用H2嵌入式数据库搭建测试环境,验证读取器的完整功能:

  1. 添加H2测试依赖(Maven):
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>test</scope>
</dependency>
  1. 编写集成测试类:
@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.ANY)
public class RelatorioReaderTest {

    @Autowired
    private DataSource dataSource;

    @Autowired
    @Qualifier("relatorioreader")
    @StepScope
    private ItemReader<Relatorio> itemReader;

    @Test
    public void test_itemReader() {
        assertNotNull(itemReader);
    }

    // 测试读取数据逻辑
    @Test
    public void test_readData() throws Exception {
        // 插入测试数据
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.update("INSERT INTO myTable (ID, date) VALUES (1, '2023-02-16')");

        // 读取数据并验证
        Relatorio item = itemReader.read();
        assertNotNull(item);
        assertEquals(1, item.getId());
    }
}

内容的提问来源于stack exchange,提问作者Erico Souza

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 03:18:24