-
Type:
New Feature
-
Status: Resolved
-
Priority:
Minor
-
Resolution: Complete
-
Affects Version/s: 4.0.1
-
Component/s: Test
-
Labels:
-
Pull Request URL:
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?