I have a Chunk Tasklet
with a reader and writer, and I am trying to make a Unit Test for it, but I face multiples issues.
I used the answer of the question below, to help creating my Unit Test:
How define a spring batch chunk in the tasklet with code
Its seems to be the closest to, what I want to make.
@ContextConfiguration(locations = { "classpath:config/beans-unittest-service.xml",
"classpath:config/beans-unittest-item.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class KpiMetricFromCsvFileTaskletTest extends RegistryServiceImplTest {
@Autowired
@Qualifier("kpiMetricCsvItemReader")
ItemReader<KpiMetric> reader;
@Autowired
@Qualifier("kpiMetricCreatorWriter")
KpiMetricCreatorWriter writer;
@Override
@Before
public void init() {
writer.setRegistryService(registryService);
writer.setRegistry(registry);
setCreateKpiMeasureBehaviour();
}
private ChunkContext createChunkContext() {
StepExecution stepExecution = Mockito.mock(StepExecution.class);
StepContext stepContext = Mockito.mock(StepContext.class);
ChunkContext chunkContext = Mockito.mock(ChunkContext.class);
JobExecution jobExecution = MetaDataInstanceFactory.createJobExecution();
Mockito.when(chunkContext.getStepContext()).thenReturn(stepContext);
Mockito.when(stepContext.getStepExecution()).thenReturn(stepExecution);
Mockito.when(stepExecution.getJobExecution()).thenReturn(jobExecution);
return chunkContext;
}
@Test
public void testTasklet() throws Exception {
StepContribution contribution = Mockito.mock(StepContribution.class);
ChunkContext chunkContext = createChunkContext();
Tasklet tasklet = new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
KpiMetric kpi = reader.read();
List<KpiMetric> items = new ArrayList<>();
while (kpi != null) {
items.add(kpi);
}
writer.write(items);
return RepeatStatus.FINISHED;
}
};
tasklet.execute(contribution, chunkContext);
}
}
- My Unit Test
Class
extends anotherClass
, that contains methods, that will set the mock object behaviour. - I have two configuration files. One of them contains a reader bean
kpiMetricCsvItemReader
and a writer beankpiMetricCreatorWriter
. - In my Unit Test
init
method, I change the service attribute of my writer to a mock service object, I also mock the context objects, just like in the answer of the link above.
The problem is that, in the testTasklet
method, I want to create a Tasklet and execute it, but when I run the program, I get the error:
org.springframework.batch.item.ReaderNotOpenException: Reader must be open before it can be read.
I understand that the file is not opened, but when I launch my Job with Spring Batch, I don't get that error, so Spring should be opening my file by itself.
Now to solve this, I should either manage to open the file for the reader or delegate the creation of the tasklet to something else, that will handle it, but how?
EDIT
Perhaps showing the reader configuration file should help :
<bean id="kpiMetricCsvItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="classpath:${kpiMetricCsvFile}" />
<property name="linesToSkip" value="1"/>
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="delimiter" value=";"/>
<property name="names" value="key,description,name,score,tool,variable_type" />
</bean>
</property>
<property name="fieldSetMapper">
<bean class="com.example.fieldmapper.KpiMetricFieldSetMapper" />
</property>
</bean>
</property>
</bean>
<bean id="kpiMetricCreatorWriter" class="com.example.writer.kpi.KpiMetricCreatorWriter" >
<property name="registry" ref="registry" />
<property name="registryService" ref="registryService" />
</bean>