Springbatch单元测试Notes
@SpringBatchTest 注解
这个注解会注册JobLauncherTestUtils和JobRepositoryTestUtils到上下文context中 因此,有两种方式 方式1:SpringBatchTest
@SpringBatchTest
@RunWith(SpringRunner.class)
@ContextConfiguration(classes:{otherClass.class})
public class SkipSampleFunctionalTests { ... }
方式2:SpringJUnit4ClassRunner
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes:{JobLauncherTestUtils.class,
JobRepositoryTestUtils.class,
otherClass.class})
public class SkipSampleFunctionalTests { ... }
Springbatch整合Mybatis-plus单元测试并回滚数据
springboot整合mybatis-plus单元测试
如果是在springboot对mybatis-plus进行单元测试,那么需要在测试类上进行以下设置:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {someClasses.class})
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.AUTO_CONFIGURED)
@MybatisPlusTest
@MapperScan(basePackages = {"com.xxx.xxx.dao"})
public class xxTest{
@Test
public void testXXX(){
}
@TestConfiguration
public static class MyConfiguration{
@Bean("dataSource")
@ConfigurationProperties(prefix = "data-source")
public DataSource dataSource(){
return new DruidDataSource();
}
@Bean
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception{
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(dataSource);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
String mapperLocation = "classpath:mapper/**/*Mapper*.xml";
bean.setMapperLocations(resolver.getResources(mapperLocation));
return bean.getObject();
}
}
}
其中,@MybatisPlusTest
注解中配置了很多注解,基本上可以一键完成springboot+mybatis的单元测试,并且可以使用数据库数据,并完成数据回滚。
如果去掉@MybatisPlusTest
,需要自行添加@Transactional
注解来控制事务,使数据回滚。而且,@ConfigurationProperties
注解会失效:当使用.properties
配置文件时,需要在配置类上添加@TestPropertySource(location={"classpath:xxx.properties"})
的注解和@EnableConfigurationProperties
的注解;当使用.yml
配置文件时,需要在测试类上添加@ContextConfiguration(initializers = {ConfigFileApplicationContextInitializer.class})
的内容。
在springboot 2.6版本中,
ConfigFileApplicationContextInitializer
更新为ConfigDataApplicationContextInitializer
总而言之,@MybatisPlusTest
进行了很多操作,便于整合到springboot的单元测试之中。
@MybatisPlusTest
中有@AutoConfigureTestDatabase
注解,但该注解默认值为AutoConfigureTestDatabase.Replace.ANY
,在我的测试中,AUTO_CONFIGURED
才起作用。
springboot整合springbatch单元测试
如果是在springboot对springbatch进行单元测试,那么需要在测试类上进行以下设置:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes:{JobLauncherTestUtils.class,
JobRepositoryTestUtils.class,
otherClass.class})
@EnableBatchProcessing
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.AUTO_CONFIGURED)
public class SkipSampleFunctionalTests {
@Test
public void testXXX(){
}
@TestConfiguration
public static class MyConfiguration{
@Bean("dataSource")
@ConfigurationProperties(prefix = "data-source")
public DataSource dataSource(){
return new DruidDataSource();
}
}
}
其中,@EnableBatchProcessing
注解完成了很多事,包括事务管理transactionManager
、jobRepository
、jobBuilderFactory
、stepBuilderFactory
、jobLauncher
、jobExplorer
等等。它是依靠注入了SimpleBatchConfiguration
完成的。
如果去掉@EnableBatchProcessing
注解,那么需要手动配置。如下所示:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes:{JobLauncherTestUtils.class,
JobRepositoryTestUtils.class,
otherClass.class})
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.AUTO_CONFIGURED)
public class SkipSampleFunctionalTests {
@Test
public void testXXX(){
}
@TestConfiguration
public static class MyConfiguration{
@Bean("dataSource")
@ConfigurationProperties(prefix = "data-source")
public DataSource dataSource(){
return new DruidDataSource();
}
@Bean("transactionManager")
public PlatformTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean(@Qualifier("transactionManager") PlatformTransactionManager transactionManager) throws Exception {
MapJobRepositoryFactoryBean factoryBean = new MapJobRepositoryFactoryBean();
factoryBean.setTransactionManager(transactionManager);
factoryBean.afterPropertiesSet();
return factoryBean;
}
@Bean("jobRepository")
public JobRepository jobRepository(@Qualifier("mapJobRepositoryFactoryBean") MapJobRepositoryFactoryBean factoryBean) throws Exception{
return factoryBean.getObject();
}
@Bean
public JobBuilderFactory jobBuilderFactory(@Qualifier("jobRepository") JobRepository jobRepository){
return new JobBuilderFactory(jobRepository);
}
@Bean
public StepBuilderFactory stepBuilderFactory(@Qualifier("transactionManager") PlatformTransactionManager transactionManager,
@Qualifier("jobRepository") JobRepository jobRepository){
return new StepBuilderFactory(jobRepository, transactionManager);
}
@Bean
public JobLauncher jobLauncher(@Qualifier("jobRepository") JobRepository jobRepository){
SimpleJobLauncher launcher = new SimpleJobLauncher();
launcher.setJobRepository(jobRepository);
return launcher;
}
@Bean
public JobExplorer jobExplorer(@Qualifier("mapJobRepositoryFactoryBean") MapJobRepositoryFactoryBean factoryBean){
return new SimpleJobExplorer(factoryBean.getJobInstanceDao(), factoryBean.getJobExecutionDao(),
factoryBean.getStepExecutionDao(), factoryBean.getExecutionContextDao());
}
}
}
并且,即使加上了@EnableBatchProcessing
注解,也可以通过重写batchConfigurer
自定义加载上述bean,如下所示:
/*
因为@EnableBatchProcessing引入了SimpleBatchConfiguration,
而SimpleBatchConfiguration中配置了名为transactionManager的事务管理器,
因此要将上文中定义的transactionManager重命名
*/
@Bean("myTransactionManager")
public PlatformTransactionManager myTransactionManager(@Qualifier("dataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public BatchConfigurer batchConfigurer(MapJobRepositoryFactoryBean mapJobRepositoryFactory,
PlatformTransactionManager myTransactionManager,
JobLauncher jobLauncher,
JobExplorer jobExplorer) {
return new BatchConfigurer() {
@Override
public JobRepository getJobRepository() throws Exception {
return mapJobRepositoryFactory.getObject();
}
@Override
public PlatformTransactionManager getTransactionManager() throws Exception {
return transactionManager;
}
@Override
public JobLauncher getJobLauncher() throws Exception {
return jobLauncher;
}
@Override
public JobExplorer getJobExplorer() throws Exception {
return jobExplorer;
}
};
}
上述代码连接了数据库,但实际中并不推荐。因为单用springbatch的注解进行单元测试,不能数据回滚,在网上并没有找到相关的办法,因此推荐连接内存数据库使用。如果批处理任务是读文件写入数据库或者从数据库写出到文件,那么这种单元测试足够了。但是,如果批处理任务涉及多张数据表查询操作,那么构造数据可能会是一个大问题。
springboot+springbatch+mybatis-plus整合进行单元测试
先抛出问题,同时使用@EnableBatchProcessing
和@MybatisPlusTest
会有事务冲突。
解决办法,很简单,但从两个很方便的注解直接入手查资料,着实很废时间,这里不卖关子,直接给出答案。
@Bean
public MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean(@Qualifier("transactionManager") PlatformTransactionManager transactionManager) throws Exception {
MapJobRepositoryFactoryBean factoryBean = new MapJobRepositoryFactoryBean();
factoryBean.setTransactionManager(transactionManager);
factoryBean.setValidateTransactionState(false); // 在这里
factoryBean.afterPropertiesSet();
return factoryBean;
}
这一行,就行了。setValidateTransactionState(false)
的作用是禁用在使用MapJobRepositoryFactoryBean时对事务状态的验证。这意味着在使用该工厂创建的 JobRepository 时,不会检查当前事务状态是否为活动状态。之后,是否使用@EnableBatchProcessing
和@MybatisPlusTest
注解,都无所谓了。这样也可以发现,可以拿到很多个版本的单元测试代码。