在 Spring - "Writer must be open before it can be written to" 异常之外对 FlatFileItemWriter 进行单元测试

unit testing a FlatFileItemWriter outside of Spring - "Writer must be open before it can be written to" exception

我正在编写一个写入 CSV 文件的简单批处理,我想为此使用 Spring 批处理 FlatFileItemWriter,使用 Spring Boot 2.3。1.RELEASE .

我想对我的 writer 进行单元测试,以便确认它的配置是否正确。

代码很简单:

    public class CSVResultWriter implements ItemWriter<Project> {

    private final FlatFileItemWriter writer;

    public CSVResultWriter(String outputResource) {

      writer=new FlatFileItemWriterBuilder<Project>()
          .name("itemWriter")
          .resource(new FileSystemResource(outputResource))
          .lineAggregator(new PassThroughLineAggregator<>())
          .append(true)
          .build();

    }

   @Override
   public void write(List<? extends Project> items) throws Exception {
     writer.write(items);
   }
}

我正在编写一个没有 Spring 的简单单元测试,例如:

    File generatedCsvFile = new File(workingDir.toString() + File.separator + "outputData.csv");

    CSVResultWriter writer = new CSVResultWriter(generatedCsvFile.getAbsolutePath());

    Project sampleProject = Project.builder().name("sampleProject1").build();

    writer.write(List.of(sampleProject));

    assertThat(generatedCsvFile).exists();

但是测试失败说:

org.springframework.batch.item.WriterNotOpenException: Writer must be open before it can be written to

查看 Spring 源代码,我不明白如何让它工作。尝试编写项目时,Spring 做的第一件事是检查编写器已初始化:

https://github.com/spring-projects/spring-batch/blob/744d1834fe313204f06c0bcd0eedd472ab4af6be/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/AbstractFileItemWriter.java#L237

    @Override
    public void write(List<? extends T> items) throws Exception {
        if (!getOutputState().isInitialized()) {
            throw new WriterNotOpenException("Writer must be open before it can be written to");
        }
...

但是 OutputState 的构建方式并没有给出它已经启动的机会:

https://github.com/spring-projects/spring-batch/blob/744d1834fe313204f06c0bcd0eedd472ab4af6be/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/AbstractFileItemWriter.java#L363

    // Returns object representing state.
    protected OutputState getOutputState() {
        if (state == null) {
            File file;
            try {
                file = resource.getFile();
            }
            catch (IOException e) {
                throw new ItemStreamException("Could not convert resource to file: [" + resource + "]", e);
            }
            Assert.state(!file.exists() || file.canWrite(), "Resource is not writable: [" + resource + "]");
            state = new OutputState();
            state.setDeleteIfExists(shouldDeleteIfExists);
            state.setAppendAllowed(append);
            state.setEncoding(encoding);
        }
        return state;
    }

--> OutputState 中的 initialized 标志保留其默认值,即 false。

所以我有点困惑..我想当它由 Spring 管理时,一些神奇的事情发生了并且它起作用了。

我是不是遗漏了一些明显的东西,或者我们真的不能在 Spring 之外测试它吗?

FlatFileItemWriter 实现了 ItemStream 合同,在 Spring 批处理作业中使用时将自动兑现。

如果您想在 Spring 之外使用编写器,您需要手动调用这些方法 (open/update/close)。这在参考文档的 Item Stream 部分中提到:

Clients of an ItemReader that also implement ItemStream should call open before any calls
to read, in order to open any resources such as files or to obtain connections.
A similar restriction applies to an ItemWriter that implements ItemStream