Skip to content

Spring Batch 单元测试指南

单元测试是确保批处理作业可靠性的关键环节。本教程将使用 Kotlin 和注解配置,通过 spring-batch-test 模块简化测试流程。


🧪 一、创建单元测试类

使用注解加载作业上下文并注入测试工具:

kotlin
@SpringBatchTest
@SpringJUnitConfig(SkipSampleConfiguration::class)
class SkipSampleFunctionalTests {

    @Autowired
    lateinit var jobLauncherTestUtils: JobLauncherTestUtils

    // 注意:当有多个Job Bean时需手动指定测试对象
    @Test
    fun setupJob(@Autowired job: Job) {
        jobLauncherTestUtils.job = job
    }
}

关键注解说明

  • @SpringJUnitConfig:启用 Spring 的 JUnit 测试支持
  • @SpringBatchTest:自动注入 JobLauncherTestUtils 等测试工具

🔁 二、端到端作业测试

完整测试作业从启动到结束的全流程:

kotlin
@Test
fun testEndToEndJob() {
    // 1. 准备测试数据
    jdbcTemplate.update("DELETE FROM CUSTOMER")
    (1..10).forEach { i ->
        jdbcTemplate.update(
            "INSERT INTO CUSTOMER VALUES (?, 0, ?, 100000)",
            i, "customer$i"
        )
    }

    // 2. 启动作业并验证结果
    val jobExecution = jobLauncherTestUtils.launchJob()
    assertEquals("COMPLETED", jobExecution.exitStatus.exitCode)
}

⚙️ 三、测试单个步骤

对复杂作业中的特定步骤进行精准测试:

kotlin
@Test
fun testSingleStep() {
    val stepExecution = jobLauncherTestUtils.launchStep("fileProcessingStep")

    // 验证步骤指标
    assertEquals(100, stepExecution.readCount)
    assertEquals(0, stepExecution.filterCount)
    assertEquals(100, stepExecution.writeCount)
}

隔离测试要点

  1. 仅初始化该步骤所需数据
  2. 直接验证 StepExecution 中的指标数据
  3. 避免依赖其他步骤的输出

🎯 四、测试步骤作用域组件

测试依赖步骤上下文的组件(如 ItemReader):

kotlin
@SpringBatchTest
@SpringJUnitConfig
class StepScopeIntegrationTests {

    @Autowired
    lateinit var reader: ItemReader<String> // 步骤作用域组件

    // 提供模拟的步骤上下文
    fun getStepExecution(): StepExecution {
        return MetaDataInstanceFactory.createStepExecution().apply {
            executionContext.putString("input.data", "A,B,C,D")
        }
    }

    @Test
    fun testReader() {
        assertNotNull(reader.read()) // 验证组件行为
    }
}

作用域激活原理

@SpringBatchTest 自动添加 StepScopeTestExecutionListener,通过 getStepExecution() 方法模拟真实步骤上下文


🧩 五、模拟领域对象

使用 MetaDataInstanceFactory 简化领域对象创建:

kotlin
@Test
fun testNoWorkFoundListener() {
    // 传统方式需手动构造多层对象
    // val stepExecution = StepExecution("step", JobExecution(JobInstance(...)))

    // 推荐方式:工厂快速创建
    val stepExecution = MetaDataInstanceFactory.createStepExecution()
    stepExecution.readCount = 0

    val exitStatus = NoWorkFoundStepExecutionListener().afterStep(stepExecution)
    assertEquals(ExitStatus.FAILED.exitCode, exitStatus.exitCode)
}
领域对象工厂方法清单
kotlin
// 常用工厂方法
MetaDataInstanceFactory.createJobExecution()
MetaDataInstanceFactory.createStepExecution()
MetaDataInstanceFactory.createJobParameters()

✅ 最佳实践总结

场景工具示例
完整作业测试JobLauncherTestUtils.launchJob()端到端测试
步骤隔离测试launchStep("stepName")单步骤测试
作用域组件测试@SpringBatchTest + 上下文工厂步骤作用域测试
领域对象模拟MetaDataInstanceFactory对象模拟

测试效率提升技巧

  1. 使用 @MockBean 模拟外部服务依赖
  2. 对长时间运行作业启用 @DirtiesContext 重置状态
  3. 结合 TestEntityManager 验证数据库变更

通过本指南,您可系统掌握 Spring Batch 组件的测试方法,确保批处理作业在生产环境中的可靠性。