web-dev-qa-db-fra.com

Comment tester Spring @Scheduled

Comment tester @Scheduled tâches dans mon application spring-boot?

 package com.myco.tasks;

 public class MyTask {
     @Scheduled(fixedRate=1000)
     public void work() {
         // task execution logic
     }
 }
14
S Puddin

Si nous supposons que votre travail s'exécute à un intervalle si réduit que vous voulez vraiment que votre test attende l'exécution du travail et que vous souhaitiez simplement vérifier si le travail est appelé, vous pouvez utiliser la solution suivante:

Ajouter Attente au classpath:

<dependency>
    <groupId>org.awaitility</groupId>
    <artifactId>awaitility</artifactId>
    <version>3.1.0</version>
    <scope>test</scope>
</dependency>

Rédiger un test similaire à:

@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());
    }
}
14
Maciej Walkowiak

C'est souvent difficile. Vous pouvez envisager de charger le contexte Spring lors du test et de simuler un bean pour vérifier l’appel planifié.

J'ai un tel exemple dans mon repo Github. Il existe un exemple simple programmé testé avec l’approche décrite.

2
luboskrnac

cette classe signifie générer des ordonnanceurs cron à l'aide de l'ordonnancement springframework

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));
        }

    }
}

voici la journalisation de sortie:

<com.medici.scheduler.jobs.TrimestralReportSenderJobTest> - lun, gen 1, 2018 at 12:02:02 AM
<com.medici.scheduler.jobs.TrimestralReportSenderJobTest> - lun, gen 1, 2018 at 03:02:02 AM
<com.medici.scheduler.jobs.TrimestralReportSenderJobTest> - lun, gen 1, 2018 at 06:02:02 AM
<com.medici.scheduler.jobs.TrimestralReportSenderJobTest> - lun, gen 1, 2018 at 09:02:02 AM
<com.medici.scheduler.jobs.TrimestralReportSenderJobTest> - lun, gen 1, 2018 at 12:02:02 PM
1
Tiago Medici

La question est "que voulez-vous tester".

Si votre réponse est "Je veux savoir que Spring exécute ma tâche planifiée quand je le souhaite", alors vous testez Spring, Pas votre code . Ce n'est pas quelque chose dont vous avez besoin à l'unité de test.

Si votre réponse est "Je veux savoir que j'ai configuré ma tâche correctement", Ensuite, écrivez une application de test avec une tâche fréquemment exécutée et vérifiez que La tâche est exécutée à l'heure prévue. n’est pas un test unitaire, mais vous montrera que vous savez configurer votre texte correctement.

Si la réponse est "Je veux savoir que la tâche que j'ai écrite fonctionne correctement", Vous devez alors tester la méthode de la tâche par test . Dans votre exemple, Vous souhaitez tester par unité la méthode work(). Faites ceci en écrivant un test unitaire qui appelle directement votre méthode de tâche (work()) . Par exemple,

public class TestMyTask
{
  @InjectMocks
  private MyTask classToTest;

  // Declare any mocks you need.
  @Mock
  private Blammy mockBlammy;

  @Before
  public void preTestSetup()
  {
    MockitoAnnotations.initMocks(this);

    ... any other setup you need.
  }

  @Test
  public void work_success()
  {
    ... setup for the test.


    classToTest.work();


    .. asserts to verify that the work method functioned correctly.
  }
1
DwB

Nous pouvons utiliser au moins deux approches pour tester les tâches planifiées avec Spring:

  • Test d'intégration

Si nous utilisons Spring Boot, nous aurons besoin des dépendances suivantes:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
</dependency>

Nous pourrions ajouter une count à la Task et l'incrémenter dans la méthode work:

 public class MyTask {
   private final AtomicInteger count = new AtomicInteger(0);

   @Scheduled(fixedRate=1000)
   public void work(){
     this.count.incrementAndGet();
   }

   public int getInvocationCount() {
    return this.count.get();
   }
 }

Puis vérifiez la count:

@SpringJUnitConfig(ScheduledConfig.class)
public class ScheduledIntegrationTest {

    @Autowired
    MyTask task;

    @Test
    public void givenSleepBy100ms_whenWork_thenInvocationCountIsGreaterThanZero() 
      throws InterruptedException {
        Thread.sleep(2000L);

        assertThat(task.getInvocationCount()).isGreaterThan(0);
    }
}
  • Une autre alternative consiste à utiliser Awaitility comme dans les mentions @ maciej-walkowiak. 

Dans ce cas, nous devons ajouter la dépendance Awaitility:

<dependency>
    <groupId>org.awaitility</groupId>
    <artifactId>awaitility</artifactId>
    <version>3.1.6</version>
    <scope>test</scope>
</dependency>

Et utilisez son DSL pour vérifier le nombre d'appels de la méthode work:

@SpringJUnitConfig(ScheduledConfig.class)
public class ScheduledAwaitilityIntegrationTest {

    @SpyBean 
    MyTask task;

    @Test
    public void whenWaitOneSecond_thenWorkIsCalledAtLeastThreeTimes() {
        await()
          .atMost(Duration.FIVE_SECONDS)
          .untilAsserted(() -> verify(task, atLeast(3)).work());
    }
}

Nous devons tenir compte du fait que même s’ils sont bons il est préférable de se concentrer sur le test unitaire de la logique dans la méthode de travail}.

Je mets un exemple ici .

0
SHoko