如何测试Spring @Scheduled

如何测试spring-boot应用程序的@ Scheduled / cron作业?

package com.myco.tasks; public class MyTask { @Scheduled(fixedRate=1000) public void work() { // task execution logic } } 

如果我们假设您的作业运行时间很短,您确实希望测试等待作业执行,并且您只想测试作业是否被调用,则可以使用以下解决方案:

将Awaitility添加到类路径:

  org.awaitility awaitility 3.1.0 test  

写测试类似于:

 @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @SpyBean private MyTask myTask; @Test public void jobRuns() { await().atMost(Duration.FIVE_SECONDS) .untilAsserted(() -> verify(myTask, times(1)).work()); } } 

这通常很难。 您可以考虑在测试期间加载Spring上下文并伪造一些bean以便能够validation计划的调用。

我在Github回购中有这样的例子。 使用所描述的方法测试了简单的预定示例。

这个类代表使用springframework调度生成调度程序cron

 import org.apache.log4j.Logger; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.scheduling.support.CronSequenceGenerator; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @RunWith(SpringJUnit4ClassRunner.class) @Configuration @PropertySource("classpath:application.properties") public class TrimestralReportSenderJobTest extends AbstractJUnit4SpringContextTests { protected Logger LOG = Logger.getLogger(getClass()); private static final String DATE_CURRENT_2018_01_01 = "2018-01-01"; private static final String SCHEDULER_TWO_MIN_PERIOD = "2 0/2 * * * *"; private static final String SCHEDULER_QUARTER_SEASON_PERIOD = "0 0 20 1-7 1,4,7,10 FRI"; @Test public void cronSchedulerGenerator_0() { cronSchedulerGenerator(SCHEDULER_QUARTER_SEASON_PERIOD, 100); } @Test public void cronSchedulerGenerator_1() { cronSchedulerGenerator(SCHEDULER_TWO_MIN_PERIOD, 200); } public void cronSchedulerGenerator(String paramScheduler, int index) { CronSequenceGenerator cronGen = new CronSequenceGenerator(paramScheduler); java.util.Date date = java.sql.Date.valueOf(DATE_CURRENT_2018_01_01); for (int i = 0; i < index; i++) { date = cronGen.next(date); LOG.info(new java.text.SimpleDateFormat("EEE, MMM d, yyyy 'at' hh:mm:ss a").format(date)); } } } 

这是输出记录:

  - lun, gen 1, 2018 at 12:02:02 AM  - lun, gen 1, 2018 at 03:02:02 AM  - lun, gen 1, 2018 at 06:02:02 AM  - lun, gen 1, 2018 at 09:02:02 AM  - lun, gen 1, 2018 at 12:02:02 PM 

Maciej Walkowiak提到的解决方案工作正常,但变化很小。 @SpyBean不能为我工作,所以我使用了@autowired,它运行得很好。