web-dev-qa-db-fra.com

Désactiver @EnableScheduling sur les tests de printemps

Lorsque j'exécute mes tests unitaires, il appelle mes tâches planifiées. Je souhaite empêcher ce comportement, qui est dû au fait que j'ai @EnableScheduling sur la configuration principale de mon application.

Comment puis-je désactiver cela sur mes tests unitaires?

Je suis tombé sur ce question/réponse qui suggère la mise en place de profils?

Vous ne savez pas comment j'y arriverais? ou si c'est une exagération? Je pensais avoir une AppConfiguration distincte pour mes tests unitaires mais j'ai l'impression de répéter deux fois le code quand je fais ça?

@Configuration
@EnableJpaRepositories(AppConfiguration.DAO_PACKAGE)
@EnableTransactionManagement
@EnableScheduling
@ComponentScan({AppConfiguration.SERVICE_PACKAGE,
                AppConfiguration.DAO_PACKAGE,
                AppConfiguration.CLIENT_PACKAGE,
                AppConfiguration.SCHEDULE_PACKAGE})
public class AppConfiguration {

    static final    String MAIN_PACKAGE             = "com.etc.app-name";
    static final    String DAO_PACKAGE              = "com.etc.app-name.dao";
    private static  final  String ENTITIES_PACKAGE  = "com.etc.app-name.entity";
    static final    String SERVICE_PACKAGE          = "com.etc.app-name.service";
    static final    String CLIENT_PACKAGE           = "com.etc.app-name.client";
    static final    String SCHEDULE_PACKAGE         = "com.etc.app-name.scheduling";


    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
       // stripped code for question readability
    }

    // more app config code below etc

}

Exemple de test unitaire.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={AppConfiguration.class})
@Transactional
@TransactionConfiguration(defaultRollback = true)
@WebAppConfiguration
public class ExampleDaoTest {

    @Autowired
    ExampleDao exampleDao;

    @Test
    public void testExampleDao() {
        List<Example> items = exampleDao.findAll();
        Assert.assertTrue(items.size()>0);
    }
}
42
Robbo_UK

Si vous ne souhaitez pas utiliser de profils, vous pouvez ajouter un indicateur qui activera/désactivera la planification pour l'application

Dans votre AppConfiguration ajoutez ceci

  @ConditionalOnProperty(
     value = "app.scheduling.enable", havingValue = "true", matchIfMissing = true
  )
  @Configuration
  @EnableScheduling
  public static class SchedulingConfiguration {
  }

et dans votre test, ajoutez simplement cette annotation pour désactiver la planification

@TestPropertySource(properties = "app.scheduling.enable=false")
40
Marko Vranjkovic

Une alternative serait de désenregistrer le post-processeur de bean qui planifie les événements. Cela peut être fait en plaçant simplement la classe suivante sur le chemin de classe de vos tests:

public class UnregisterScheduledProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException {
        for (String beanName : beanFactory.getBeanNamesForType(ScheduledAnnotationBeanPostProcessor.class)) {
            ((DefaultListableBeanFactory)beanFactory).removeBeanDefinition(beanName);
        }
    }
}

Bien que cela soit assez simple et semble faire le travail, sachez que je n'ai pas beaucoup testé cela ou vérifié les implications possibles de la suppression d'un bean défini du registre ou de m'assurer que la commande de PostProcessors ne sera pas un problème ...

11
yankee

Je viens de paramétrer mon annotation @Scheduled avec des temps de retard configurables:

@Scheduled(fixedRateString = "${timing.updateData}", initialDelayString = "${timing.initialDelay}")

Dans mon test application.yaml:

timing:
    updateData: 60000
    initialDelay: 10000000000

Et application.yaml principale:

timing:
    updateData: 60000
    initialDelay: 1

Il ne s'agit pas de l'éteindre mais de créer un délai si long, les tests seront terminés avant son exécution. Pas la solution la plus élégante mais certainement l'une des plus faciles que j'ai trouvées.

9
Laila Sharshar

Dans chaque test, vous définissez la configuration de ressort à utiliser, vous avez actuellement:

@ContextConfiguration(classes={AppConfiguration.class})

La pratique courante consiste à définir une configuration de ressort distincte pour votre application normale et pour vos tests.

AppConfiguration.Java 
TestConfiguration.Java

Ensuite, dans votre test, vous référencez simplement TestConfiguration à la place de votre AppConfiguration actuel en utilisant @ContextConfiguration(classes={TestConfiguration.class})

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={TestConfiguration.class})
@Transactional
@TransactionConfiguration(defaultRollback = true)
@WebAppConfiguration
public class ExampleDaoTest

De cette façon, vous pouvez configurer n'importe quel paramètre pour vos tests différemment du code de production. Vous pouvez par exemple utiliser une base de données en mémoire pour vos tests au lieu d'une base de données régulière et bien plus encore.

2
Vojtech Ruzicka

J'ai pu résoudre ce problème en créant une méthode qui supprime les tâches planifiées lors des tests unitaires. Voici un exemple:

    import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;
    import org.springframework.context.ApplicationContext;

    public static void removeSchedulledTasks(ScheduledAnnotationBeanPostProcessor postProcessor, ApplicationContext appContext) {

    postProcessor.setApplicationContext(appContext);

    Iterator<ScheduledTask> iterator = postProcessor.getScheduledTasks().iterator();

    while(iterator.hasNext()) {

        ScheduledTask taskAtual = iterator.next();
        taskAtual.cancel();

    }

}

Exemple d'utilisation:

import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.Utils;


@RunWith(SpringRunner.class)
@SpringBootTest
public class TestRemoveScheduller {


    @Autowired
    private ScheduledAnnotationBeanPostProcessor postProcessor;

    @Autowired
    private ApplicationContext appContext;


    @Before
    public void init(){

        //Some init variables

        //Remove schedulled tasks method
        Utils.removeSchedulledTasks(postProcessor, appContext);

    }

    //Some test methods

}

J'espère que cela t'aides.

1
Gladson Bruno