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?