如何用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嵌入式数据库搭建测试环境,验证读取器的完整功能:
- 添加H2测试依赖(Maven):
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>test</scope> </dependency>
- 编写集成测试类:
@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
相关产品推荐
相关产品推荐

