Spring Batch中Tasklet抛异常但assertThrows测试失败问题求助
Spring Batch任务抛出异常但测试断言失败的问题
我在Tasklet的execute()方法中根据条件抛出IllegalStateException,并编写了如下测试用例验证批处理作业:
@Test void testJobThrowsMyException() throws Exception { JobParameters emptyJobParameters = new JobParameters(); assertThrows(IllegalStateException.class, () -> jobLauncherTestUtils.launchJob(emptyJobParameters)); }
execute方法代码如下:
@Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) { getWorkload(chunkContext).forEach(workloadItem -> { // Processing }); return RepeatStatus.FINISHED; }
获取workload的逻辑大致如下:
private int getWorkload() { if (condition) { throw new IllegalStateException("Thats the exception i want to test"); } return workload; }
问题在于,从测试执行日志可以看到异常已抛出,但测试却失败,提示:
org.opentest4j.AssertionFailedError: Expected java.lang.IllegalStateException to be thrown, but nothing was thrown.
日志明确显示异常已抛出:
10:32:54.608 [main] DEBUG org.hibernate.loader.Loader - Result row: 10:32:54.616 [main] DEBUG org.springframework.batch.core.step.tasklet.TaskletStep - Applying contribution: [StepContribution: read=0, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING] 10:32:54.616 [main] DEBUG org.springframework.batch.core.step.tasklet.TaskletStep - Rollback for RuntimeException: java.lang.IllegalStateException: Es ist noch keine Liefernummer in den ImportDetails vorhanden. 10:32:54.618 [main] DEBUG org.springframework.transaction.support.TransactionTemplate - Initiating transaction rollback on application exception java.lang.IllegalStateException: Thats the exception i want to test at [...] 10:32:54.619 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Initiating transaction rollback 10:32:54.619 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Rolling back JPA transaction on EntityManager [SessionImpl(1793816221<open>)] 10:32:54.619 [main] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - rolling back 10:32:54.620 [main] DEBUG org.springframework.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [SessionImpl(1793816221<open>)] after transaction 10:32:54.621 [main] DEBUG org.springframework.batch.repeat.support.RepeatTemplate - Handling exception: java.lang.IllegalStateException, caused by: java.lang.IllegalStateException: Es ist noch keine Liefernummer in den ImportDetails vorhanden. 10:32:54.621 [main] DEBUG org.springframework.batch.repeat.support.RepeatTemplate - Handling fatal exception explicitly (rethrowing first of 1): java.lang.IllegalStateException: Es ist noch keine Liefernummer in den ImportDetails vorhanden. 10:32:54.622 [main] ERROR org.springframework.batch.core.step.AbstractStep - Encountered an error executing step my-step in job my-job
我并未捕获该异常,请问为何测试会失败?望解答,谢谢。
原因分析
Spring Batch在执行完整作业时,会将任务流程封装在事务管理和异常处理逻辑中。当Tasklet抛出IllegalStateException后,框架会先触发事务回滚,随后不会将原始异常直接抛给jobLauncherTestUtils.launchJob()的调用者,而是把异常信息封装到返回的JobExecution对象中。
launchJob()方法本身不会抛出业务代码产生的异常,只会返回包含失败状态和异常详情的JobExecution实例,这就是assertThrows断言失败的核心原因——没有异常从该方法直接抛出。
解决方案
你需要通过JobExecution的状态和异常信息来验证测试结果,而非直接断言方法抛出异常:
@Test void testJobThrowsMyException() throws Exception { JobParameters emptyJobParameters = new JobParameters(); JobExecution jobExecution = jobLauncherTestUtils.launchJob(emptyJobParameters); // 验证作业执行状态为失败 Assertions.assertEquals(BatchStatus.FAILED, jobExecution.getStatus()); // 验证失败原因是目标异常 Assertions.assertInstanceOf(IllegalStateException.class, jobExecution.getAllFailureExceptions().get(0)); // 可选:验证异常消息匹配 Assertions.assertEquals("Thats the exception i want to test", jobExecution.getAllFailureExceptions().get(0).getMessage()); }
如果希望直接捕获到原始异常,可以改为测试单个步骤——launchStep()方法会将步骤执行时抛出的异常直接向上传递:
@Test void testStepThrowsMyException() throws Exception { JobParameters emptyJobParameters = new JobParameters(); Assertions.assertThrows(IllegalStateException.class, () -> jobLauncherTestUtils.launchStep("my-step", emptyJobParameters)); }
内容的提问来源于stack exchange,提问作者Manu
相关产品推荐
相关产品推荐

