Uploaded image for project: 'Spring Batch'
  1. Spring Batch
  2. BATCH-2718

Simplify batch test utilities configuration

    Details

      Description

      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?

        Attachments

          Activity

            People

            • Assignee:
              mbenhassine Mahmoud Ben Hassine
              Reporter:
              mbenhassine Mahmoud Ben Hassine
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: