Cucumber JUnit 5 avec Spring

Si vous cherchez à migrer Cucumber de JUnit 4 à JUnit 5 ou si tout simplement, vous voulez mettre en place Cucumber avec JUnit 5 sur votre projet, vous êtes au bon endroit !

Thibaut Debruille nous avait écrit un très bon article sur l’utilisation de contextes Spring séparés dans les tests Cucumber.

Je viens donc compléter ses propros avec l’utilisation de JUnit 5.

Recette de cuisine

Pour ce faire, nous allons avoir besoin de quelques dépendances :

  • org.junit.jupiter:junit-jupiter
  • org.junit.platform:junit-platform-suite
  • io.cucumber:cucumber-java
  • io.cucumber:cucumber-spring
  • io.cucumber:cucumber-junit-platform-engine

Pour résumer, nous allons utiliser la plate-forme JUnit 5 et les extensions Cucumber qui vont avec.

Vous pouvez remarquer que le temps de org.junit.vintage.junit-vintage-engine est révolu, adieu JUnit 4 !

Structure du projet

Nous allons retrouver dans resources/features les dossiers et sous-dossiers qui vont contenir nos fonctionnalités rédigées en Gherkin, les fameux .features.

Dans src/test/java/com.example.features, nous aurons la configuration pour démarrer nos tests Cucumber.  Dans un sous-package steps, nous aurons nos classes d’implémentation des gherkins.

// RunFeatureTests.java

package com.example.features;

import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;
import static io.cucumber.junit.platform.engine.Constants._GLUE_PROPERTY_NAME_;
import static io.cucumber.junit.platform.engine.Constants._PLUGIN_PROPERTY_NAME_;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;

@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("features")
@ConfigurationParameter(key = _GLUE_PROPERTY_NAME_, value = "com.example.features")
@ConfigurationParameter(key = _PLUGIN_PROPERTY_NAME_, value = "pretty, json:target/cucumber.json")
final class RunFeatureTests {

    @SpringBootTest(classes = FeatureBeanDefinitions.class)
    @ActiveProfiles(value = "features")
    @CucumberContextConfiguration
    static class FeatureSpringConfig {
    }

    @TestConfiguration
    static class FeatureBeanDefinitions {
      // Bean definitions goes here with @Bean
      // This class could be extracted in its own file
    }

}

Les annotations @Suite et @IncludeEngines vont respectivement préparer l’exécution de la plateforme JUnit 5 et l’informer de l’extension Cucumber.

L’annotation @SelectClasspathResource permet de dissocier les fichiers Gherkin de leur implémentation. Effectivement, par défaut, Cucumber s’attend à ce que les deux se trouvent dans le même dossier / le même package. Ici, j’ai volontairement séparé les deux, pour une question de lisibilité et également parce que je n’aime pas l’idée d’associer mes fichiers de feature à l’arborescence technique du projet.

L’annotation @ConfigurationParameter permet de paramétrer l’exécution de Cucumber. Ici, nous allons générer un rapport en json et nous précisons également la glue entre nos fichiers de feature et leur implémentation (les classes du dossier steps). Pour affecter plusieurs glues, il suffit de séparer les chemins par des virgules.

Notez par ailleurs qu’il est de facto possible de créer plusieurs classes d’exécution avec des glues différentes. C’est très avantageux quand vous avez des pans fonctionnels différents au sein d’un même projet et que vous voulez isoler leur contexte de tests.

Les annotations de la classe interne FeatureSpringConfig permettent d’indiquer à Cucumber que nous allons utiliser le contexte Spring pour exécuter nos tests. Pour faciliter la configuration Spring, nous utilisons un profil features dédié (qui nous permettra d’avoir notamment un fichier application-features.yml) et une classe FeatureBeanDefinitions pour avoir la main sur l’instanciation de nos beans. Instancier manuellement les beans est d’ailleurs une bonne pratique que l’on retrouve dans la Clean Architecture.

Il n’y a plus qu’à exécuter la classe RunFeatureTests et le tour est joué !

Que devient le fichier cucumber.properties ?

Maintenant que les tests sont exécutés avec la plateforme JUnit, l’usage du fichier cucumber.properties n’est plus nécessaire. En effet, les paramètres sont passés avec l’annotation @ConfigurationParameter. Il est toutefois possible de définir un fichier junit-platform.properties pour le paramétrage qui serait plus global et transverse à nos test suites.

Conclusion

Nous sommes maintenant en mesure de profiter pleinement de la plateforme JUnit 5 et de Cucumber pour exécuter nos tests fonctionnels. Le contexte Spring permet d’être au plus proche du fonctionnement réel de l’application, tout en bornant nos tests grâce à l’instanciation de nos beans dans une configuration dédiée.

Références