|
对于最新稳定版本,请使用Spring Batch Documentation 6.0.0! |
单元测试
与其他应用风格一样,对任何编写的代码进行单元测试极为重要
作为批量作业的一部分。Spring核心文档涵盖了如何进行单位化和集成
用Spring做了非常详细的测试,所以这里不会重复。然而,这很重要,
思考如何“端到端”测试批次作业,这正是本章所涵盖的内容。
这Spring Batch测试项目包含促进这一端到端测试的课程
方法。
创建单元测试类
为了让单元测试运行批处理作业,框架必须加载该作业的应用上下文.触发该行为使用了两种注释:
-
@SpringJUnitConfig表示该班应该使用 Spring 的 JUnit 设施 -
@SpringBatchTest注入 Spring Batch 测试工具(例如JobLauncherTestUtils和JobRepositoryTestUtils)在测试语境中
如果测试上下文包含单个工作豆子的定义,就是这个
豆子会被自动接线JobLauncherTestUtils.否则,工作就好
被测时应手动设置JobLauncherTestUtils. |
-
Java
-
XML
以下 Java 示例展示了所使用的注释:
@SpringBatchTest
@SpringJUnitConfig(SkipSampleConfiguration.class)
public class SkipSampleFunctionalTests { ... }
以下XML示例展示了所使用的注释:
@SpringBatchTest
@SpringJUnitConfig(locations = { "/simple-job-launcher-context.xml",
"/jobs/skipSampleJob.xml" })
public class SkipSampleFunctionalTests { ... }
批处理作业的端到端测试
“端到端”测试可以定义为测试一个批处理作业的整个运行过程,从 从头到尾。这允许测试设置测试条件,执行作业, 并验证最终结果。
举一个批处理作业的例子,它从数据库读取并写入一个平面文件。
测试方法首先是用测试数据建立数据库。它清除了客户端然后插入10条新记录。测试随后发射工作通过使用launchJob()方法。这launchJob()方法由JobLauncherTestUtils类。这JobLauncherTestUtils类还提供launchJob(JobParameters)该方法允许检验给出特定参数。这launchJob()方法
返回作业执行对象,用于断言特定信息
关于工作跑。在以下情况下,检验验证了工作结尾为
一个完成.
-
Java
-
XML
以下列表展示了 Java 配置风格下的 JUnit 5 示例:
@SpringBatchTest
@SpringJUnitConfig(SkipSampleConfiguration.class)
public class SkipSampleFunctionalTests {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
private JdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Test
public void testJob(@Autowired Job job) throws Exception {
this.jobLauncherTestUtils.setJob(job);
this.jdbcTemplate.update("delete from CUSTOMER");
for (int i = 1; i <= 10; i++) {
this.jdbcTemplate.update("insert into CUSTOMER values (?, 0, ?, 100000)",
i, "customer" + i);
}
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
Assert.assertEquals("COMPLETED", jobExecution.getExitStatus().getExitCode());
}
}
以下列表展示了 JUnit 5 的 XML 配置样式示例:
@SpringBatchTest
@SpringJUnitConfig(locations = { "/simple-job-launcher-context.xml",
"/jobs/skipSampleJob.xml" })
public class SkipSampleFunctionalTests {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
private JdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Test
public void testJob(@Autowired Job job) throws Exception {
this.jobLauncherTestUtils.setJob(job);
this.jdbcTemplate.update("delete from CUSTOMER");
for (int i = 1; i <= 10; i++) {
this.jdbcTemplate.update("insert into CUSTOMER values (?, 0, ?, 100000)",
i, "customer" + i);
}
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
Assert.assertEquals("COMPLETED", jobExecution.getExitStatus().getExitCode());
}
}
测试单个步骤
对于复杂的批处理作业,端到端测试方法中的测试用例可能会变成
不可收拾。在这些情况下,使用测试用例来测试个体可能更有用
自己走。这JobLauncherTestUtils类包含一个称为launchStep,
该步长取一个步名,并运行该步步.这种方法允许
更有针对性测试,允许测试仅为该步骤设置数据并验证其
直接结果。以下示例展示了如何使用launchStep加载方法步姓名:
JobExecution jobExecution = jobLauncherTestUtils.launchStep("loadFileStep");
测试步骤范围组件
通常,为你的步骤配置的组件在运行时会使用步骤作用域和
延迟绑定用于从步骤或作业执行中注入上下文。这些测试很棘手,因为
独立组件,除非你有办法把上下文设置成一个步骤
执行。这是Spring Batch两个组成部分的目标:StepScopeTestExecutionListener和StepScopeTestUtils.
监听器在类级声明,其任务是创建一个步骤执行 每种测试方法的上下文,如下示例所示:
@SpringJUnitConfig
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class,
StepScopeTestExecutionListener.class })
public class StepScopeTestExecutionListenerIntegrationTests {
// This component is defined step-scoped, so it cannot be injected unless
// a step is active...
@Autowired
private ItemReader<String> reader;
public StepExecution getStepExecution() {
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
execution.getExecutionContext().putString("input.data", "foo,bar,spam");
return execution;
}
@Test
public void testReader() {
// The reader is initialized and bound to the input data
assertNotNull(reader.read());
}
}
有两个测试执行监听器.其中之一是常规的春季测试框架,其中
从配置的应用上下文中处理依赖注入以注入读卡器。
另一个是春季批StepScopeTestExecutionListener.它的工作原理是寻找
工厂方法在测试案例中步执行,以此为上下文
测试方法,就像该执行在步在运行时。工厂方法
通过其签名检测到(必须返回步执行).如果工厂方法为
未提供,默认步执行被创造出来。
从 v4.1 开始,StepScopeTestExecutionListener和JobScopeTestExecutionListener作为测试执行监听器导入
如果测试类被注释为@SpringBatchTest.前述测试
示例可以配置如下:
@SpringBatchTest
@SpringJUnitConfig
public class StepScopeTestExecutionListenerIntegrationTests {
// This component is defined step-scoped, so it cannot be injected unless
// a step is active...
@Autowired
private ItemReader<String> reader;
public StepExecution getStepExecution() {
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
execution.getExecutionContext().putString("input.data", "foo,bar,spam");
return execution;
}
@Test
public void testReader() {
// The reader is initialized and bound to the input data
assertNotNull(reader.read());
}
}
如果你希望步长作用波的时长为
测试方法的执行。如果想要更灵活但更具侵入性的治疗方法,你可以使用
这StepScopeTestUtils.以下示例统计了可用物品的数量
前面示例中展示的读者:
int count = StepScopeTestUtils.doInStepScope(stepExecution,
new Callable<Integer>() {
public Integer call() throws Exception {
int count = 0;
while (reader.read() != null) {
count++;
}
return count;
}
});
模拟域对象
在为 Spring Batch 编写单元测试和集成测试时,另一个常见问题
组件是如何模拟域对象。一个很好的例子是StepExecutionListener如
以下代码片段显示:
public class NoWorkFoundStepExecutionListener implements StepExecutionListener {
public ExitStatus afterStep(StepExecution stepExecution) {
if (stepExecution.getReadCount() == 0) {
return ExitStatus.FAILED;
}
return null;
}
}
该框架提供了前面的监听者示例,并检查步执行对于空读计数,表示没有完成任何工作。虽然这个例子是
它相当简单,旨在说明你可能遇到的问题类型
你尝试单元测试实现需要 Spring Batch 域接口的类
对象。请考虑前述示例中听者的以下单元测试:
private NoWorkFoundStepExecutionListener tested = new NoWorkFoundStepExecutionListener();
@Test
public void noWork() {
StepExecution stepExecution = new StepExecution("NoProcessingStep",
new JobExecution(new JobInstance(1L, new JobParameters(),
"NoProcessingJob")));
stepExecution.setExitStatus(ExitStatus.COMPLETED);
stepExecution.setReadCount(0);
ExitStatus exitStatus = tested.afterStep(stepExecution);
assertEquals(ExitStatus.FAILED.getExitCode(), exitStatus.getExitCode());
}
由于Spring Batch域模型遵循了良好的面向对象原则,步执行需要一个作业执行,这需要一个JobInstance和作业参数,以创建有效的步执行.虽然这在稳固的领域是好的
它确实让创建单元测试的存根对象变得冗长。为了解决这个问题,
Spring Batch测试模块包含一个用于创建域对象的工厂:MetaDataInstanceFactory.鉴于该工厂,单元测试可以更新为更多
简洁,如下例所示:
private NoWorkFoundStepExecutionListener tested = new NoWorkFoundStepExecutionListener();
@Test
public void testAfterStep() {
StepExecution stepExecution = MetaDataInstanceFactory.createStepExecution();
stepExecution.setExitStatus(ExitStatus.COMPLETED);
stepExecution.setReadCount(0);
ExitStatus exitStatus = tested.afterStep(stepExecution);
assertEquals(ExitStatus.FAILED.getExitCode(), exitStatus.getExitCode());
}
前述创建简单方法步执行只有一种方便方法。
工厂内可获得。你可以在其Java文档中找到完整的方法列表。