如何测试Quarkus定时调度任务,验证其在指定时间运行
Quarkus定时任务测试方案(针对柏林时间3点执行的清理任务)
问题场景
我在Java Quarkus应用中编写了如下类与数据清理方法,该方法通过Quarkus定时调度注解配置为每天柏林时间3点执行:
@ApplicationScoped public class DeprecatedDataRemovalBean { private static final Logger LOG = Logger.getLogger(DeprecatedDataRemovalBean.class); @Inject JobService jobService; //at 3 o'clock in the morning @Scheduled(cron = "0 0 3 * * ?", timeZone = "Europe/Berlin") void removeDeprecatedData(ScheduledExecution execution) { LOG.info("Starting the data removal at " + execution.getScheduledFireTime()); try { jobService.removeDataIfReadCountIsMoreThanOne(); LOG.info("Data removal process completed successfully."); } catch (Exception e) { LOG.error("An error occurred during the data removal process: ", e); } } }
希望编写测试用例,将系统时间设置为3点,验证该定时任务确实会在此时运行,但之前尝试的测试均未成功,求可行方案。
可行测试方案
Quarkus提供了专门的定时任务测试支持,结合时间模拟和依赖注入Mock,可以完成验证,具体步骤如下:
1. 添加必要依赖
确保pom.xml(Maven)或build.gradle(Gradle)中包含Quarkus测试相关依赖:
<!-- Maven --> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-junit5</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <scope>test</scope> </dependency>
2. 编写测试类
使用@QuarkusTest启动测试容器,通过@InjectMock替代真实的JobService,并利用Quarkus的调度器时间模拟功能控制系统时间:
import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.mockito.InjectMock; import io.quarkus.scheduler.Scheduler; import org.junit.jupiter.api.Test; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.Instant; import static org.mockito.Mockito.verify; @QuarkusTest public class DeprecatedDataRemovalBeanTest { @InjectMock JobService jobService; @Inject Scheduler scheduler; @Test void testScheduledDataRemovalAtBerlin3AM() throws InterruptedException { // 构造柏林时间凌晨3点的时间点 ZonedDateTime berlin3AM = ZonedDateTime.now(ZoneId.of("Europe/Berlin")) .withHour(3) .withMinute(0) .withSecond(0) .withNano(0); Instant targetTime = berlin3AM.toInstant(); // 开启调度器的时间模拟并设置目标时间 scheduler.mockTime().setTime(targetTime); // 触发调度器立即检查待执行任务 scheduler.evaluateJobs(); // 短暂等待任务执行完成 Thread.sleep(1000); // 验证JobService的清理方法是否被调用 verify(jobService).removeDataIfReadCountIsMoreThanOne(); } }
3. 关键说明
- 时间模拟:Quarkus调度器原生支持
mockTime()方法,无需额外扩展即可模拟系统时间,精准匹配定时任务的时区配置。 - Mock依赖:用
@InjectMock替代真实业务服务,避免测试时操作生产数据,同时方便验证方法调用情况。 - 主动触发检查:调用
scheduler.evaluateJobs()让调度器立即扫描任务,无需等待自然时间流逝到3点。 - 时区对齐:明确使用
Europe/Berlin时区构造目标时间,确保和定时任务的时区配置完全一致,避免时区差导致的触发失败。
备选方案:直接测试业务逻辑
如果仅需验证清理方法的业务正确性,无需验证调度器的触发逻辑,可以直接调用目标方法:
import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.mockito.InjectMock; import org.junit.jupiter.api.Test; import static org.mockito.Mockito.verify; @QuarkusTest public class DeprecatedDataRemovalBeanDirectTest { @Inject DeprecatedDataRemovalBean removalBean; @InjectMock JobService jobService; @Test void testDataRemovalLogic() { // 直接调用清理方法,传入null或模拟ScheduledExecution对象 removalBean.removeDeprecatedData(null); // 验证业务方法是否被执行 verify(jobService).removeDataIfReadCountIsMoreThanOne(); } }
内容的提问来源于stack exchange,提问作者Grigor
相关产品推荐
相关产品推荐

