当前位置: 首页 > 知识库问答 >
问题:

如何成功地为Spring批处理JUnit5测试的Spring任务加载JobLauncherTestUtils类

祁凯泽
2023-03-14

对于spring批处理测试,我有一个看似简单的配置。但是,测试无法加载上下文。该错误告诉我存在一个与数据源相关的不可解析循环引用。如果移除数据源,则错误将更改为未定义数据源。我所要实现的只是能够加载JobLauncherTestUtils,然后启动一个用于测试步骤的作业。它看起来很简单,但要加载一个简单的工作来进行测试却非常困难。我正在Java12、Spring5和spring batch 2.2.0发行版和JUnit5(Jupiter)上运行spring Boot2。配置有什么问题?我需要做什么改变。我认为您不必指定数据源配置,但如果不配置数据源,就无法实现加载。这是我的配置。我真的很感谢你帮我弄清楚我的配置有什么问题。我的目标只是成功地自动生成JobLauncherTestUtils类。

like 

class BatchTest {
   @Autowired
   JobLauncherTestUtils jobLauncherTestUtils;
}


import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.batch.test.context.SpringBatchTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;


@ExtendWith(SpringExtension.class)
@SpringBatchTest
@ContextConfiguration(classes = {BatchTest.BatchConfiguration.class, 
BatchAutoConfiguration.class})
@TestPropertySource(properties = "debug=true")
public class BatchTest {

@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;

@Test
public void test() {
    this.jobLauncherTestUtils.launchStep("orderProcessingJob");
    //assertions 
}

    @Configuration
    @EnableBatchProcessing
    public static class BatchConfiguration {

    private  JobBuilderFactory jobBuilderFactory;

    @Bean(name="jobLauncherTestUtils")
    public JobLauncherTestUtils jobLauncherTestUtils() throws Exception {
        JobLauncherTestUtils jl = new JobLauncherTestUtils();
        jl.setJobLauncher(jobLauncher());
        jl.setJob(orderProcessorJob());
        jl.setJobRepository(jobRepository().getObject());
        return jl;
    }

        @Bean
        public JobRepositoryFactoryBean jobRepository() {
        JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
        jobRepositoryFactoryBean.setDataSource(dataSource());
        return jobRepositoryFactoryBean;
      }


    @Bean
    public Job orderProcessorJob() {
        return jobBuilderFactory.get("orderProcessingJob")
                .incrementer(new RunIdIncrementer())
                .flow(orderIntakeStep())
                .end()
                .build();
    }

    private Step orderIntakeStep() {
        // code for order Intake
    }

    @Bean
    public JobLauncher jobLauncher() throws Exception {
        SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
        jobLauncher.setJobRepository(jobRepository().getObject());
        return jobLauncher;
    }


    private  StepBuilderFactory stepBuilderFactory;


    @Bean
    public EmbeddedDatabase dataSource() {
        return new EmbeddedDatabaseBuilder().build();
    }


    @Autowired
    public BatchConfiguration(JobBuilderFactory jobBuilderFactory , 
                                          StepBuilderFactory stepBuilderFactory) {
        this.jobBuilderFactory = jobBuilderFactory;
        this.stepBuilderFactory = stepBuilderFactory;
     }

    }
 }

原因:org.springframework.beans.factory.UnsatisfiedDependencyException:创建名为“BatchTest.BatchConfiguration”的bean时出错:

通过构造函数参数0表示的未满足的依赖项;嵌套异常

是org.springframework.beans.factory.unsatisfiedDependencyException:创建名为“org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration”的bean时出错:

通过字段“Data Source”表示的未满足的依赖关系;嵌套异常为org.SpringFramework.Beans.Factory.BeanCurrentlyIncreationException:

创建名为“BatchTest.BatchConfiguration”的bean时出错:请求的bean当前正在创建中:是否存在不可解析的循环引用?

共有1个答案

融渊
2023-03-14

通过字段“Data Source”表示的未满足的依赖关系;嵌套异常为org.SpringFramework.Beans.Factory.BeanCurrentlyIncreationException:

创建名为“BatchTest.BatchConfiguration”的bean时出错:请求的bean当前正在创建中:是否存在不可解析的循环引用?

您试图在BatchConfiguration#jobRepository()中注入的数据源是在同一类(datasource()方法)中创建的,因此出现错误。您需要在一个单独的类中提取数据源配置,如下所示:

@Configuration
public static class DataSourceConfig {
   @Bean
   public EmbeddedDatabase dataSource() {
      return new EmbeddedDatabaseBuilder().build();
   }
}
@Configuration
@Import(DataSourceConfig.class)
@EnableBatchProcessing
public static class BatchConfiguration {

   // ..       

   @Bean
   public JobRepositoryFactoryBean jobRepository(DataSource dataSource) {
      JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
      jobRepositoryFactoryBean.setDataSource(dataSource);
       return jobRepositoryFactoryBean;
  }
  
  // ..
}

我的目标只是成功地自动生成JobLauncherTestUtils类。

由于您使用的是@SpringBatchTest,因此不需要手动创建JobLauncherTestUtils(在您的JobLauncherTestUtils()方法中),这个注释的目标是为您导入它,查看它的Javadoc。下面是一个典型的用法:

@RunWith(SpringRunner.class)
@SpringBatchTest
@ContextConfiguration(classes = MyBatchJobConfiguration.class)
public class MyBatchJobTests {

    @@Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;

    @@Autowired
    private JobRepositoryTestUtils jobRepositoryTestUtils;

    @Before
    public void clearJobExecutions() {
        this.jobRepositoryTestUtils.removeJobExecutions();
    }

    @Test
    public void testMyJob() throws Exception {
        // given
        JobParameters jobParameters = this.jobLauncherTestUtils.getUniqueJobParameters();

        // when
        JobExecution jobExecution = this.jobLauncherTestUtils.launchJob(jobParameters);

        // then
        Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
    }

}
 类似资料:
  • 我正在寻找一些关于测试Spring批处理步骤和步骤执行的一般性意见和建议。 我的基本步骤是从api读入数据,处理实体对象,然后写入数据库。我已经测试了快乐之路,这一步成功地完成了。我现在想做的是在处理器阶段数据丢失时测试异常处理。我可以单独测试processor类,但我更愿意测试整个步骤,以确保在步骤/作业级别正确反映流程故障。 我已经阅读了spring批量测试指南,如果我是诚实的,我对它有点迷茫

  • 我试图在JUnit 5和SpringBatchTest注释中加载JobLauncherTestUtils对象。但是,它无法加载应用程序上下文。所有其他自动构建的bean都成功加载,但是JobLauncherTestUtils无法加载。这是我的测试配置,省略了导入。我尝试在BeforeAll中手动加载它,但是JobRepository和JobLauncher无法加载。我只对能够成功实例化JobLau

  • 我编写了一个简单的spring批处理tasklet,它调用一个dao方法,该方法反过来执行一些删除操作。但我不确定该怎么称呼这份工作。 到目前为止,为了执行我的spring批处理作业,我使用了类似于这样的设置的quartz触发器。每个作业都有自己的xml文件,该文件具有读写器。 然后这里是一个作业文件本身的示例,包含一个读写器。 显然,这份新工作没有读者或作家。那么,我执行新任务的最佳/正确方式是

  • 我有写入数据库的Spring Batch作业(它有一个带有的步骤)。我有一个联调,如下所示: 在测试中运行作业时,它会提交到数据库。如何防止提交到数据库?通常,我可以添加以在每次测试后回滚事务。但是,当我将注释添加到测试类时,我收到: 使现代化 我试图将添加到测试类中。但是,仍然提交。 以下是应用程序代码中事务管理器的配置:

  • 有一个基于某些条件删除文件的任务。这个任务应该每天在某个时间运行。我们是否应该为这个任务使用spring boot和调度器。或者spring批处理+调度器会很好。也可以在spring批处理中使用分区并行处理此任务。 谢谢

  • 我们目前正在将一个复杂的spring boot batch+admin UI系统迁移到一个spring-cloud-task基础设施中,该基础设施将被管理云数据流。 作为POC的第一阶段,我们必须能够将所有Spring批处理作业打包在同一个部署JAR下,并且能够使用自定义作业参数一个接一个地运行它们,并且支持某种REST API远程执行作业/任务。 我们删除了所有spring-batch管理依赖项