【问题标题】:How to successfullky load the JobLauncherTestUtils class for a Spring Task for a Spring Batch JUnit 5 Test如何为 Spring Batch JUnit 5 测试的 Spring 任务成功加载 JobLauncherTestUtils 类
【发布时间】:2020-07-21 04:14:05
【问题描述】:

我有这个看似简单的弹簧批量测试配置。但是,测试无法加载上下文。该错误告诉我存在与数据源相关的无法解析的循环引用。如果我删除数据源,则错误会更改为尚未定义数据源。我想要实现的只是能够加载 JobLauncherTestUtils 然后启动一个作业来测试这些步骤。看起来很简单,但是加载一个简单的工作进行测试却非常困难。我在 Java 12 和 spring 5 以及 spring batch 2.2.0.RELEASE 和 JUnit 5 (Jupiter) 上运行 spring boot 2。配置有什么问题?我需要做些什么改变。我认为您不一定必须指定数据源配置,但如果不配置一个,它根本不会接近加载。这是我的配置。我真的很感激能帮助我弄清楚我的配置出了什么问题。我的目标只是成功地自动装配 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 时出错:

通过字段'dataSource'表达的不满足的依赖关系;嵌套异常是 org.springframework.beans.factory.BeanCurrentlyInCreationException:

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

【问题讨论】:

  • 为什么BatchAutoConfiguration.class 中有@ContextConfiguration

标签: spring spring-boot junit spring-batch


【解决方案1】:

通过字段'dataSource'表达的不满足的依赖关系;嵌套异常是 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();
   }
}

然后将其导入您的BatchConfiguration:

@Configuration
@Import(DataSourceConfig.class)
@EnableBatchProcessing
public static class BatchConfiguration {

   // ..       

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

我建议将基础设施 bean 与业务逻辑 bean 分开。也就是说,由于您使用的是@EnableBatchProcessing,因此无需自己配置作业存储库、作业启动器等。此注解的目标是为您提供这些基础设施 bean,请参阅 its javadoc

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

由于您使用的是@SpringBatchTest,因此无需手动创建JobLauncherTestUtils(在您的jobLauncherTestUtils() 方法中),此注解的目标是为您导入它,请参阅its 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());
    }

}

【讨论】:

  • 非常感谢,我将尝试使用 ExtendWith(SpringExtension.class) 解决您的问题。非常感谢!
猜你喜欢
  • 2020-07-17
  • 2017-07-28
  • 2019-02-27
  • 2016-03-16
  • 2021-05-20
  • 1970-01-01
  • 2018-09-27
  • 2015-03-24
  • 1970-01-01
相关资源
最近更新 更多