Spring Batch -单元测试
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Batch -单元测试相关的知识,希望对你有一定的参考价值。
与其他应用程序样式一样,对编写的任何代码进行单元测试非常重要。 作为批处理作业的一部分。Spring 核心文档涵盖了如何单元和集成 用 Spring 进行了非常详细的测试,因此这里不再重复。然而,重要的是, 思考如何“端到端”测试批处理作业,这就是本章介绍的内容。 该项目包括促进此端到端测试的类 方法。spring-batch-test
创建单元测试类
要使单元测试运行批处理作业,框架必须加载作业的 .两个批注用于触发此行为:ApplicationContext
-
@SpringJUnitConfig
指示类应使用 Spring 的 JUnit 设施 -
@SpringBatchTest
在测试上下文中注入 Spring 批处理测试实用程序(例如 和 )JobLauncherTestUtils
JobRepositoryTestUtils
如果测试上下文包含单个 Bean 定义,则此 Bean 将在 中自动连线。否则,作业 应在 上手动设置“测试”。 |
以下 Java 示例显示了正在使用的注释:
使用 Java 配置
@SpringBatchTest
@SpringJUnitConfig(SkipSampleConfiguration.class)
public class SkipSampleFunctionalTests ...
以下 XML 示例显示了正在使用的批注:
使用 XML 配置
@SpringBatchTest
@SpringJUnitConfig(locations = "/simple-job-launcher-context.xml",
"/jobs/skipSampleJob.xml" )
public class SkipSampleFunctionalTests ...
批处理作业的端到端测试
“端到端”测试可以定义为测试批处理作业的完整运行 从头到尾。这允许设置测试条件、执行作业、 并验证最终结果。
考虑一个从数据库读取并写入平面文件的批处理作业示例。 测试方法首先使用测试数据设置数据库。它清除表,然后插入 10 条新记录。然后,测试使用该方法启动 。该方法由类提供。该类还提供了方法,该方法允许测试给出特定的参数。方法 返回对象,这对于断言特定信息很有用 关于运行。在以下情况下,测试验证 状态为 。CUSTOMER
Job
launchJob()
launchJob()
JobLauncherTestUtils
JobLauncherTestUtils
launchJob(JobParameters)
launchJob()
JobExecution
Job
Job
COMPLETED
以下清单显示了 XML 配置样式中的 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());
以下清单显示了 Java 配置样式中的 JUnit 5 示例:
基于 Java 的配置
@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());
测试各个步骤
对于复杂的批处理作业,端到端测试方法中的测试用例可能会变成 不可收拾。在这些情况下,使用测试用例来测试单个可能更有用 自己踩踏。该类包含一个名为 的方法。 它采用步骤名称并仅运行该特定.这种方法允许 更有针对性的测试,让测试只为该步骤设置数据并验证其 直接结果。下面的示例演示如何使用该方法按名称加载AbstractJobTests
launchStep
Step
launchStep
Step
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());
有两个.一个是常规的弹簧测试框架,它 处理来自配置的应用程序上下文的依赖项注入以注入读取器。 另一个是春季批次。它通过寻找一个 测试用例中的工厂方法,使用它作为 测试方法,就好像该执行在运行时处于活动状态一样。工厂方法 通过其签名检测到(它必须返回 )。如果工厂方法是 未提供,则创建默认值。TestExecutionListeners
StepScopeTestExecutionListener
StepExecution
Step
StepExecution
StepExecution
从 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 提供了一个调用的类,用于方便验证输出文件。称为 takes 的方法 两个对象(或两个对象),并逐行断言这两个 文件具有相同的内容。因此,可以创建一个具有预期 输出并将其与实际结果进行比较,如以下示例所示:AssertFile
assertFileEquals
File
Resource
private static final String EXPECTED_FILE = "src/main/resources/data/input.txt";
private static final String OUTPUT_FILE = "target/test-outputs/output.txt";
AssertFile.assertFileEquals(new FileSystemResource(EXPECTED_FILE),
new FileSystemResource(OUTPUT_FILE));
模拟域对象
为 Spring 批处理编写单元和集成测试时遇到的另一个常见问题 组件是如何模拟域对象。一个很好的例子是 ,作为 以下代码片段显示:StepExecutionListener
public class NoWorkFoundStepExecutionListener extends StepExecutionListenerSupport
public ExitStatus afterStep(StepExecution stepExecution)
if (stepExecution.getReadCount() == 0)
return ExitStatus.FAILED;
return null;
该框架提供了前面的侦听器示例,并检查 的读取计数是否为空,从而表示未完成任何工作。虽然这个例子是 相当简单,它用于说明您在以下情况下可能遇到的问题类型 您尝试单元测试类,这些类实现需要 Spring 批处理域的接口 对象。请考虑前面示例中侦听器的以下单元测试:StepExecution
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 域模型遵循良好的面向对象原则,因此需要 ,这需要 和 才能创建有效的 .虽然这在坚实的领域很好 模型,它确实使为单元测试创建存根对象变得冗长。为了解决这个问题, Spring 批处理测试模块包括一个用于创建域对象的工厂:。给定此工厂,单元测试可以更新为更多 简洁,如以下示例所示:StepExecution
JobExecution
JobInstance
JobParameters
StepExecution
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());
前面创建简单的方法只是一种方便的方法 工厂内可用。您可以在其Javadoc中找到完整的方法列表。StepExecution
以上是关于Spring Batch -单元测试的主要内容,如果未能解决你的问题,请参考以下文章
Spring-batch:如何在 Spring Batch 中使用 skip 方法捕获异常消息?
spring batch ftp 集成超时错误 - 使用 spring-boot/spring-batch 进行 ETL
陪你解读Spring Batch带你入手Spring Batch
Spring boot spring.batch.job.enabled=false 无法识别