I am trying to unit test and individual step in Spring Batch. This step has a reader, a processor and a writer. The reader has a method annotated with @BeforeStep in order to set StepExecution.
I want to add a key to StepExecution in order to promote it to future steps using a listener. Here is my configuration:
@Configuration
@EnableBatchProcessing
public class MyJob {
@Bean
public Job myJob() {
return jobBuilderFactory.get("myJob")
.incrementer(new RunIdIncrementer())
.listener(jobIdToContextExecutionListener())
.flow(myStep())
.end()
.build();
}
@Bean
public Step myStep() {
return stepBuilderFactory.get("myStep").<MyDto, OtherDto>chunk(chunk)
.reader(myReader())
.processor(myProcessor())
.writer(myWriter(JOB_ID))
.listener(myPromotionListener())
.build();
}
@Bean
public ExecutionContextPromotionListener myPromotionListener() {
ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
listener.setKeys(new String[] {"myKey"});
return listener;
}
@Bean
@StepScope
ItemReader<DTO> myReader() {
return new MyReader();
}
@Bean
@StepScope
ItemProcessor<MyDto> myProcessor() {
return new MyProcessor();
}
}
When I want to unit test this step, I get NullPointerException for stepExecution in sendForNextSteps method. Here is the code for my ItemReader:
public class MyReader implements ItemReader<MyDto> {
private StepExecution stepExecution;
@Override
public MyDto read() {
// some logic
sendForNextSteps(someDto);
return someDto;
}
private void sendForNextSteps(MyDto myDto){
ExecutionContext stepContext = this.stepExecution.getExecutionContext();
stepContext.put("mykey", myDto);
}
@BeforeStep
public void saveStepExecution(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
}
Here is my code for the unit test:
@SpringBootTest
@ContextConfiguration(classes = {MyJob.class, JobLauncherTestUtilsWithoutDatasourceConfig.class, TransferItemService.class, DataUtils.class})
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class JobStepUnitTest {
@Test
public void myTest() {
/**
* some mocking and arrangement irrelevant of spring batch
*/
/**
* when launching myStep
*/
JobExecution jobExecution = jobLauncherTestUtils.launchStep("myStep");
/**
* some assertions on the number of calls to methods. also irrelevant to spring batch
*/
}
}
Is there any way to unit test an individual step that manipulates StepContext (for example in my code, ItemReader adds a key to the context)? I have seen examples that unit test a StepScope component like ItemReader but could not find a way to unit test the whole step. Thanks in advance.
I have also checked that answer in the following link:
but the difference is that in this link, we are testing a StepScope component. In my case, we are testing the whole step using jobLauncherTestUtils.launchStep()
. I also tried adding getStepExecution
method in my test class together with StepScopeTestExecutionListener.class for the @TestExecutionListeners
annotation but no success