Description
Mahmoud Ben Hassine opened BATCH-2718 and commented
Currently, in order to autowire and use the JobLauncherTestUtils
in a JUnit test, a bean of type JobLauncherTestUtils
should be registered in the test context:
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {JobConfiguration.class, JobTest.TestConfiguration.class})
public class JobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void testJob() throws Exception {
// given
JobParameters uniqueJobParameters = jobLauncherTestUtils.getUniqueJobParameters();
JobParameters jobParameters = new JobParametersBuilder(uniqueJobParameters)
.toJobParameters();
// when
JobExecution jobExecution = jobLauncherTestUtils.launchJob(jobParameters);
// then
Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
}
@Configuration
public static class TestConfiguration {
@Bean
public JobLauncherTestUtils jobLauncherTestUtils() {
return new JobLauncherTestUtils();
}
}
}
In this example, JobConfiguration
contains the configuration of the job under test, but as we can see, there is an additional effort required to create a configuration class, define a bean of type JobLauncherTestUtils
in it and then import it in the test context (see usage of JobRunnerConfiguration
class and job-runner-context.xml
in some tests of the current code base).
It would be great if this bean (and other test utility beans and listeners like the JobRepositoryTestUtils
, StepScopeTestExecutionListener
and JobScopeTestExecutionListener
) can be autowired in the test in a declarative way. There are multiple ways to do it and here are a couple of options I want to suggest:
Option 1: Create a new annotation @SpringBatchTest
This annotation would import a configuration class that contains batch test utilities beans. This is the same idea as SpringIntegration
test for integration. An example would be:
@RunWith(SpringRunner.class)
@SpringBatchTest
@ContextConfiguration(classes = {JobConfiguration.class})
public class JobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void testJob() throws Exception {
// given
JobParameters uniqueJobParameters = jobLauncherTestUtils.getUniqueJobParameters();
JobParameters jobParameters = new JobParametersBuilder(uniqueJobParameters)
.toJobParameters();
// when
JobExecution jobExecution = jobLauncherTestUtils.launchJob(jobParameters);
// then
Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
}
}
This annotation would also declare the StepScopeTestExecutionListener
and JobScopeTestExecutionListener
in addition to utility beans.
Option 2: Create a custom JUnit runner
I think it is also possible to create a custom batch runner that autowires the JobLauncherTestUtils
(and other utility beans and listeners) in the test context. Here is an example:
@RunWith(SpringBatchRunner.class)
@ContextConfiguration(classes = {JobConfiguration.class})
public class JobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void testJob() throws Exception {
// given
JobParameters uniqueJobParameters = jobLauncherTestUtils.getUniqueJobParameters();
JobParameters jobParameters = new JobParametersBuilder(uniqueJobParameters)
.toJobParameters();
// when
JobExecution jobExecution = jobLauncherTestUtils.launchJob(jobParameters);
// then
Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
}
}
With this option, the only concern is how to support both Junit 4 and Junit 5. AFAIK, Junit 5 has a different extension model than JUnit 4.
Option 3: Create a custom test context bootstrapper
Like option 2, it is probably possible to create a custom TestContextBootstrapper
that autowires the JobLauncherTestUtils
(and other utility beans and listeners) in the test context. Something like:
@RunWith(SpringRunner.class)
@BootstrapWith(SpringBatchTestContextBootstrapper.class)
@ContextConfiguration(classes = {JobConfiguration.class})
public class JobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void testJob() throws Exception {
// given
JobParameters uniqueJobParameters = jobLauncherTestUtils.getUniqueJobParameters();
JobParameters jobParameters = new JobParametersBuilder(uniqueJobParameters)
.toJobParameters();
// when
JobExecution jobExecution = jobLauncherTestUtils.launchJob(jobParameters);
// then
Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
}
}
With all these options, as a batch developer, I can import and autowire batch test utilities in a declarative way without having to configure them explicitly. I don't know what is the best way to implement the feature, so please let me know if there is a better option to do it. What do you think?
Affects: 4.0.1
Referenced from: pull request #605
Backported to: 4.1.0.M1