Skip to content

JUnit Tests Triggers and Tasks

Paul Sterl edited this page Mar 30, 2025 · 8 revisions

Disable SchedulerService

The SchedulerService can be disabled for unit testing, which ensures that no trigger will be executed automatically.

spring:
    persistent-tasks:
        scheduler-enabled: false

Test support @since v1.6

With 1.6 where is a PersistentTaskTestService and other helper methods like:

  • runNextTrigger
  • scheduleNextTriggersAndWait
<dependency>
    <groupId>org.sterl.spring</groupId>
    <artifactId>spring-persistent-tasks-test</artifactId>
    <version>1.x.x</version>
</dependency>

You may either include it in the component scan or build it manually in your test config:

    @TestConfiguration
    static class Config {
        @Bean
        PersistentTaskTestService persistentTaskTestService(List<SchedulerService> schedulers, TriggerService triggerService) {
            return new PersistentTaskTestService(schedulers, triggerService);
        }
    }

This class adds some test methods to wait, run or assert triggers.

Manually run one task

Now you can run any trigger manually using the TriggerService

NOTE: Using the TriggerService is recommended to see any errors which might arise.

    @Autowired
    private TriggerService triggerService;

    @Test
    void testRunTriggerDirectly() {
        // GIVEN
        // setup your test and create any triggers needed
        var trigger = TaskTriggerBuilder
                .<Vehicle>newTrigger("task2")
                .id("my-id") // will overwrite existing triggers
                .state(new Vehicle("funny"))
                .build();

        // WHEN create and directly run this trigger
        triggerService.run(triggerService.queue(trigger));

        // THEN
        // any asserts you might need
    }

    @Test
    void testRunUnknownTriggersCreated() {
        // GIVEN
        // setup your test call any method which might create triggers

        // WHEN run next pending trigger synchronously
        triggerService.run(triggerService.lockNextTrigger("test"));

        // THEN
        // any asserts you might need
    }

Run all queued tasks

Sometimes it might be useful quickly to execute all running tasks. This sample adds a method e.g. to your base test class which will trigger any task which is now due to be executed.

  @Autowired
  protected TriggerService triggerService;

  /**
   * Run all pending triggers synchronously
   */
  protected int waitForDbSchedulerTasks() {
    TriggerEntity t;
    int count = 0;
    while ((t = triggerService.lockNextTrigger("test")) != null) {
      triggerService.run(t);
      ++count;
    }
    return count;
  }

Run all queued tasks in the future & retries

A common use case is run tasks which should run in the future or just to wait that all retries are exceeded.

  @Autowired
  protected TriggerService triggerService;

  protected int waitForDbSchedulerTasks(OffsetDateTime thenToRun) {
    List<TriggerEntity> triggers;
    int count = 0;
    while (!(triggers = triggerService.lockNextTrigger("test", 1, thenToRun)).isEmpty()) {
      triggerService.run(triggers.get(0));
      ++count;
    }
    return count;
  }

Async execution of Triggers

It is also possible to define a test scheduler and use the async way to execute any triggers (without the spring scheduler which would trigger them automatically).

NOTE: Any errors are now in the log and are handled by the framework with retries etc.

@Configuration
    public static class TestConfig {
        // @Primary // if more than one
        @Bean
        SchedulerService schedulerService(
                TriggerService triggerService, 
                EditSchedulerStatusComponent editSchedulerStatus,
                TransactionTemplate trx) {

            final var taskExecutor = new TaskExecutorComponent(triggerService, 10);
            taskExecutor.setMaxShutdownWaitTime(Duration.ofSeconds(0));
            return new SchedulerService("testScheduler", triggerService, taskExecutor, editSchedulerStatus, trx);
        }
    }

Now the PersistentTaskService has a method to trigger or to trigger and to wait for the result:

    @Autowired
    private PersistentTaskService persistentTaskService;

    @Test
    void testFoo() {
        // GIVEN
        // setup your test and create any triggers needed

        // WHEN run any pending triggers asynchronously - but with and wait
        var triggerKeys = persistentTaskService.executeTriggersAndWait();
        // OR queue all triggers asynchronously - and return the futures
        var futureTriggerKeys = persistentTaskService.executeTriggers();

        // THEN
        // any asserts you might need
    }

Waiting for all task which might trigger other tasks

In some cases we have longer running triggers which may trigger new jobs. As so we have to wait.

        Awaitility.await().atMost(Duration.ofMillis(1500)).until(() -> { // set the max wait time as needed
            waitForDbSchedulerTasks();
            return //* insert here your assert for the last task you wait for */;
        });

During the setup and cleanup it is possible to cancel any pending triggers:

    @BeforeEach
    public void beforeEach() throws Exception {
        triggerService.deleteAll();
        historyService.deleteAll();
        schedulerService.setMaxThreads(10);
        schedulerService.start();
    }

    @AfterEach
    public void afterEach() throws Exception {
        // will cancel any pending tasks
        schedulerService.shutdownNow(); // use .stop() if you want to wait
    }
Clone this wiki locally