How to successfullky load the JobLauncherTestUtils class for a Spring Task for a Spring Batch JUnit 5 Test
13:12 08 Apr 2020

I have this seemingly straightforward configuration for a spring batch test. However, the test fails to load the context. The error tells me there is an unresolvable circular reference related to the datasource. If I remove the datasource, the error changes that a datasource has not been defined.

All I am trying to achieve is to be able to load the JobLauncherTestUtils and then launch a job for testing the steps. It seems simple enough but it is frustratingly difficult to load a simple job for testing. I am running a Spring Boot 2 on Java 12 and Spring 5 and spring batch 2.2.0.RELEASE and JUnit 5 (Jupiter). What's the problem with the configuration? What changes do I need to make?

I thought you would not necessarily have to specify a datasource configuration, but it simply does not come close to loading without configuring one. Here is my configuration. My objective is simply to successfully autowire the JobLauncherTestUtils class.

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;
     }
        
    }
 }

Here is the core piece of the stacktrace I am seeing:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'batchTest.BatchConfiguration':

Unsatisfied dependency expressed through constructor parameter 0; nested exception

is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration':

Unsatisfied dependency expressed through field 'dataSource'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:

Error creating bean with name 'batchTest.BatchConfiguration': Requested bean is currently in creation: Is there an unresolvable circular reference?

spring spring-boot junit spring-batch