在 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 做的第一件事是检查编写器已初始化:
@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 的构建方式并没有给出它已经启动的机会:
// 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
我正在编写一个写入 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 做的第一件事是检查编写器已初始化:
@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 的构建方式并没有给出它已经启动的机会:
// 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