I've implemented a simple job with 2 tasklets. I want to test the second tasklet by passing parameters.
I've read the Spring batch documentation and below my test:
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles({"test"})
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class,
StepScopeTestExecutionListener.class })
public class EtudeBatchApplicationTests {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
public StepExecution getStepExecution() {
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
execution.getJobExecution().getExecutionContext().putString("myValue", "foo,bar,spam");
return execution;
}
@Test
public void contextLoads() {
JobExecution jobExecution = jobLauncherTestUtils.launchStep("insertIncludedSiretsStep");
}
}
My problem is in my tasklet, the myValue is always null.
Below, the code of the tasklet:
@Component
@StepScope
@Slf4j
public class InsertIncludedSiretsTask implements Tasklet {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
Object myValue = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().get("myValue");
log.info("INSERTINCLUDEDSIRETSTASK runnning");
Thread.sleep(3000);
return RepeatStatus.FINISHED;
}
}
In order for the unit test to run a batch job, the framework must load the job's ApplicationContext. Two annotations are used to trigger this behavior: @RunWith(SpringJUnit4ClassRunner. class) : Indicates that the class should use Spring's JUnit facilities.
JobParameters can be used for identification or even as reference data during the job run. They have reserved names, so to access them we can use Spring Expression Language. For example to access a property 'abc' on job parameters: we can access it using the syntax #{jobParameters[abc]} .
In this case, there's only one step performing only one tasklet. However, that tasklet defines a reader, a writer and a processor that will act over chunks of data. Note that the commit interval indicates the amount of data to be processed in one chunk. Our job will read, process and write two lines at a time.
The correct approach for batch job integration testing is to test the job as a black box. If the job reads data from a table and writes to another table or a file, you can proceed as follows: Put some test data in the input table (Given) Run your job (When)
You can mock the ChunkContext following this example :
http://www.javased.com/index.php?source_dir=spring-insight-plugins/collection-plugins/spring-batch/src/test/java/com/springsource/insight/plugin/springbatch/TaskletCollectionAspectTest.java
Here is my code :
public ChunkContext createChunkContext() {
StepExecution stepExecution=Mockito.mock(StepExecution.class);
StepContext stepContext=Mockito.mock(StepContext.class);
ChunkContext chunkContext=Mockito.mock(ChunkContext.class);
JobExecution jobExecution= createJobExecution();
Mockito.when(chunkContext.getStepContext()).thenReturn(stepContext);
Mockito.when(stepContext.getStepExecution()).thenReturn(stepExecution);
Mockito.when(stepExecution.getJobExecution()).thenReturn(jobExecution);
return chunkContext;
}
public JobExecution createJobExecution() {
JobExecution execution = MetaDataInstanceFactory.createJobExecution();
execution.getExecutionContext().putString("myValue", "foo,bar,spam");
return execution;
}
@Test
public void testSendEmail() throws Exception {
StepContribution contribution= Mockito.mock(StepContribution.class);
ChunkContext chunkContext= createChunkContext();
sendReportTasklet.execute(contribution, chunkContext );
}
Based on Melkior answer which helped me a lot I simplify the test:
public class MyTaskletTest {
private static final String MY_JOB_PARAM = "my.job.param";
@Mock
private StepContribution stepContribution;
@Mock
private StepExecution stepExecution;
@Mock
private StepContext stepContext;
@Mock
private ChunkContext chunkContext;
private MyTasklet tasklet;
@Before
public void setupTest() {
when(chunkContext.getStepContext()).thenReturn(stepContext);
when(stepContext.getStepExecution()).thenReturn(stepExecution);
}
@Override
public void init() {
tasklet = new MyTasklet();
}
@Test
public void should_test_my_tasklet() throws Exception {
when(stepExecution.getJobParameters()).thenReturn(defaultJobParameters("myParam"));
tasklet.execute(stepContribution, chunkContext);
}
private JobParameters defaultJobParameters(String myParam) {
JobParametersBuilder paramsBuilder = new JobParametersBuilder();
paramsBuilder.addString(MY_JOB_PARAM, myParam);
return paramsBuilder.toJobParameters();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With