春季批处理:测试自定义itemReader

时间:2020-02-17 20:12:58

标签: java junit spring-batch

我正在测试我的自定义itemReader:

@Bean
@StepScope
MyMultiLineItemReader itemReader(@Value("#{stepExecutionContext['fileName']}") String filename) throws MalformedURLException {
MyMultiLineItemReader itemReader = new MyMultiLineItemReader();
itemReader.setDelegate(myFlatFileItemReader(filename));

return itemReader;
}

@Bean
@StepScope
public FlatFileItemReader<String> myFlatFileItemReader(@Value("#{stepExecutionContext['fileName']}") String filename) throws MalformedURLException {
return new FlatFileItemReaderBuilder<String>()
.name("myFlatFileItemReader")
.resource(new UrlResource(filename))
.lineMapper(new PassThroughLineMapper())
.build();
}

我的测试课看起来像

@Test
public void givenMockedStep_whenReaderCalled_thenSuccess() throws Exception {
    // given
    JobExecution jobExecution = new JobExecution(5l);
    ExecutionContext ctx = new ExecutionContext();
    ctx.put("fileName", "src/main/resources/data/input.txt");
    jobExecution.setExecutionContext(ctx);

    JobSynchronizationManager.register(jobExecution);
    StepExecution stepExecution = MetaDataInstanceFactory.createStepExecution(ctx);

    // when
    StepScopeTestUtils.doInStepScope(stepExecution, () -> {
     ...
     });
}

我运行测试用例时,该过程失败,因为fileName参数为null。

我正在寻找测试itemReader的正确方法。

谢谢

1 个答案:

答案 0 :(得分:3)

您无需创建JobExecution并将其注册到JobSynchronizationManager中即可测试步进作用域的组件。模拟一个步骤执行并在StepScopeTestUtils.doInStepScope中使用它就足够了。这是一个完整的示例:

import java.util.ArrayList;
import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.file.mapping.PassThroughLineMapper;
import org.springframework.batch.test.MetaDataInstanceFactory;
import org.springframework.batch.test.StepScopeTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = StepScopedComponentTest.MyConfiguration.class)
public class StepScopedComponentTest {

    @Autowired
    private FlatFileItemReader<String> reader;

    @Test
    public void givenMockedStep_whenReaderCalled_thenSuccess() throws Exception {
        // given
        ExecutionContext ctx = new ExecutionContext();
        ctx.put("fileName", "data/input.txt");
        StepExecution stepExecution = MetaDataInstanceFactory.createStepExecution(ctx);

        // when
        List<String> items = StepScopeTestUtils.doInStepScope(stepExecution, () -> {
            List<String> result = new ArrayList<>();
            String item;
            reader.open(stepExecution.getExecutionContext());
            while ((item = reader.read()) != null) {
                result.add(item);
            }
            reader.close();
            return result;
        });

        // then
        Assert.assertEquals(2, items.size());
        Assert.assertEquals("foo", items.get(0));
        Assert.assertEquals("bar", items.get(1));
    }

    @Configuration
    @EnableBatchProcessing
    static class MyConfiguration {

        @Bean
        @StepScope
        public FlatFileItemReader<String> myFlatFileItemReader(@Value("#{stepExecutionContext['fileName']}") String filename) {
            return new FlatFileItemReaderBuilder<String>()
                    .name("myFlatFileItemReader")
                    .resource(new ClassPathResource(filename))
                    .lineMapper(new PassThroughLineMapper())
                    .build();
        }
    }

}

假设类路径资源data/input.txt包含在行foobar中,此测试通过。