Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test individual Spring Batch Tasklet step with parameters

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;

    }
}
like image 762
ChriX Avatar asked Jun 09 '17 08:06

ChriX


People also ask

How do I test a spring boot batch job?

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.

How do you access job parameters in Spring Batch?

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]} .

What is difference between step Tasklet and chunk in Spring Batch?

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.

How do you test a batch job?

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)


2 Answers

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 );
    }
like image 163
Melkior Avatar answered Oct 11 '22 14:10

Melkior


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();
    }

}

like image 34
Guilherme Bernardi Avatar answered Oct 11 '22 16:10

Guilherme Bernardi