英文:
unit testing a FlatFileItemWriter outside of Spring - "Writer must be open before it can be written to" exception
问题
以下是您要翻译的内容:
我正在编写一个简单的批处理程序,用于编写CSV文件,我想使用Spring Batch的FlatFileItemWriter
来实现,使用的是Spring Boot 2.3.1.RELEASE版本。
我想对编写器进行单元测试,以确认它已正确配置。
代码非常简单:
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的方式并不允许标记已初始化:
// 返回表示状态的对象。
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之外进行此测试?
英文:
I am writing a simple batch that writes a CSV file, and I wanted to use Spring Batch FlatFileItemWriter
for that, using Spring Boot 2.3.1.RELEASE.
I want to unit test my writer so that I can confirm it's configured properly.
the code is very simple :
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);
}
}
and I am writing a simple unit test without Spring, something like :
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();
But the test fails saying :
org.springframework.batch.item.WriterNotOpenException: Writer must be open before it can be written to
Looking at Spring source code, I don't understand how it's possible to make it work.. When trying to write items, the first thing that Spring does is checking that the writer is initialized :
@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");
}
...
but the way OutputState is built doesn't give a chance to say it has been initiated :
// 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;
}
--> the initialized
flag in OutputState
keeps its default value, which is false.
So I am a bit puzzled.. I guess when this is managed by Spring, some magic happens and it works.
Am I missing something obvious, or can't we really test this outside of Spring ?
答案1
得分: 2
FlatFileItemWriter
实现了 ItemStream
接口,当在 Spring Batch 作业中使用时,会自动遵守该接口的约定。
如果您想在 Spring 之外使用该写入器,您需要手动调用这些方法(open/update/close)。在参考文档的 Item Stream 部分中有提到:
如果同时实现了 ItemStream 的 ItemReader 的客户端,在调用 read 之前应调用 open,以打开诸如文件或获取连接之类的任何资源。
同样的限制也适用于实现了 ItemStream 的 ItemWriter。
英文:
The FlatFileItemWriter
implements the ItemStream
contract, which will be automatically honored when used in a Spring Batch job.
If you want to use the writer outside of Spring, you need to call theses methods (open/update/close) manually. This is mentioned in the Item Stream section of the reference docs:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论