繁体   English   中英

使用 cron 属性在 Spring-boot 中测试 @Scheduled 函数

[英]Test a @Scheduled function in Spring-boot with cron property

我想测试我的 Cron-job 是否会在给定时间(每年 1 月 1 日 00:00)执行。 有没有办法测试这个? 不幸的是,我在网上找到的每个示例都指的是将在修复期后执行的作业,例如所有 5 秒。( https://www.baeldung.com/spring-testing-scheduled-annotation )。

    @Scheduled(cron = " 0 0 1 1 *")
    public void myFunc() {
         do something
    }

好吧,如果您真的想测试执行情况,您将不得不在新年前夕监视应用程序;<)

如果您想测试调度是否已正确设置并且您的任务是否已调度,那么您可以自动装配 ScheduledStaskHolder 并查询您的任务。 假设这个实现:

package nl.benooms.scheduledannotationplayground;
@Service
public class FixedDateSchedule {
    @Scheduled(cron = "0 0 0 1 1 *")
    public void OnceAYearCron() {
        System.out.println("yearly");
    }
}

那么测试可能是:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
class FixedDateScheduleTest {

    @Autowired
    private ScheduledTaskHolder scheduledTaskHolder;

    @Test
    public void testYearlyCronTaskScheduled() {
        Set<ScheduledTask> scheduledTasks = scheduledTaskHolder.getScheduledTasks();
        scheduledTasks.forEach(scheduledTask -> scheduledTask.getTask().getRunnable().getClass().getDeclaredMethods());
        long count = scheduledTasks.stream()
                .filter(scheduledTask -> scheduledTask.getTask() instanceof CronTask)
                .map(scheduledTask -> (CronTask) scheduledTask.getTask())
                .filter(cronTask -> cronTask.getExpression().equals("0 0 0 1 1 *") && cronTask.toString().equals("nl.benooms.scheduledannotationplayground.FixedDateSchedule.OnceAYearCron"))
                .count();
        assertThat(count).isEqualTo(1L);
    }
}

如果出现以下情况,测试将失败:

  • @Scheduled 或 @EnableScheduling 未设置
  • cron 表达式不准确
  • 类名和方法名不对应请注意,如果不是样本,我会将测试格式化为更易读的格式

我试图完全按照 Ben Ooms 的建议去做,但它对我不起作用。

我没有使用注释设置我的计划任务,我已经实施了一种解决方法来使用自动装配的“TaskScheduler”来安排它们,尽管它正在工作,但我无法在 ScheduledTaskHolder 中找到我的计划任务。

原来我必须声明一个 Bean 像:

@Configuration
class SchedulerConfiguration {
    @Bean
    fun threadPoolTaskScheduler(): TaskScheduler {
        val scheduler = ThreadPoolTaskScheduler()
        scheduler.poolSize = 20
        return scheduler
    }
}

并使用接口安排我的任务: SchedulingConfigurer

class MySchedulers(
    private val myService: MyService,
    @Qualifier("threadPoolTaskScheduler") private val threadPoolTaskScheduler: TaskScheduler
) : SchedulingConfigurer {

    private val logger = Logger(this::class.java)
    private val cronExpression = "0 0 10 * * *"

    override fun configureTasks(taskRegistrar: ScheduledTaskRegistrar) {
        taskRegistrar.setTaskScheduler(threadPoolTaskScheduler)

        logger.info("Setting scheduler cron=$cronExpression")
        taskRegistrar.addCronTask(CronTask({ runMyTask() }, CronTrigger(cronExpression)))
        }
    }

    private fun runMyTask() {
        myService.update()
    }
}

然后我可以按照 Ben Ooms 的建议使用 ScheduledTaskHolder 成功找到我的计划任务。

想想你真正想要测试什么

  1. 我认为您不应该测试@Scheduled是否在做它应该做的事情。 这个测试应该是 spring 框架的一部分,你不应该关心测试框架。

  2. 如果您正确应用@Scheduled可能是一个有意义的测试,并且 Ben Ooms 的答案提供了解决方案。 但是,您很可能正确地应用了它,一旦您在开发模式下运行您的应用程序,很可能会看到它是否有效。

  3. 更重要的测试,如果你的cron规范正确建模领域的需求

    a) 在我看来,它更重要,因为它很容易搞砸,因为它没有对每个值都有明确的表示法,并且与 UNIX cron 作业不同。 测试可以采用指定的注释值并检查它是否对域需求建模,即您的0 0 1 1 * -String 实际上意味着executed at 1 January 00:00 of each year

    b) 另一种测试方法是在测试期间操纵Clock以将其显式设置为预期时间并查看调度程序是否触发该方法。 然而,这可能无法捕获所有情况——尤其是误报(即调度程序可能会在预期的时刻触发,但也会在其他不应该触发的时刻触发)。

  4. 更重要的是测试调度的方法实际上做了它应该做的事情 这可以是一个简单的单元测试,但可能涉及集成测试,具体取决于域需求。 单元测试完全独立于调度机制,因此可以像任何其他单元测试一样实现(例如使用模拟运行器)。

我认为 3) 可能重要或不那么重要,具体取决于用例,而 4)始终非常重要 因此,两者都应该是测试策略的一部分。 另一方面,1) 不应该被测试,2) 很好,但可能是过度设计测试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM