Skip to content

Simplify batch test utilities configuration [BATCH-2718] #889

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue May 9, 2018 · 1 comment
Closed
Labels
has: backports Legacy label from JIRA. Superseded by "for: backport-to-x.x.x" in: test type: feature
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

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

@spring-projects-issues
Copy link
Collaborator Author

Mahmoud Ben Hassine commented

Among the 3 suggested options, option 1 (create a new annotation @SpringBatchTest) was retained. For the record, I put here the reasons we did not consider other options:

  • Option 2 (Create a custom JUnit runner): The caveat with this option is that we would have to support both JUnit 4 and JUnit 5 (which have different extension mechanisms). For JUnit 4, we need to create a custom org.junit.runner.Runner while for JUnit 5 we need to create a custom org.junit.jupiter.api.extension.Extension.
  • Option 3 (Create a custom test context bootstrapper): With this option, we would duplicate a lot of code from Spring Boot code base to register the custom beans and listeners. This option would be interesting if the functionality is implemented in Spring Boot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has: backports Legacy label from JIRA. Superseded by "for: backport-to-x.x.x" in: test type: feature
Projects
None yet
Development

No branches or pull requests

1 participant