Introduction
Junit 4 a sorti sa première version en février 2006 et sa dernière (4.12) en Décembre 2014. Il était donc grand temps de sortir une nouvelle version pour s'adapter aux standards de JAVA 8 (Et JAVA 9 qui vient de sortir) et aux besoins des développeurs en matière de tests. Cette version tant attendue est donc enfin sortie le 10 septembre 2017 et je vais donc vous présenter les grands axes de cette version et les choses qui ont retenu mon attention.
Présentation
JUnit 5 n'est plus composé d'un package unique; il est désormais découpé en 3 modules principaux qui nous permettent de n'installer que ceux dont nous avons besoin.
Ces trois packages sont les suivants :
- JUnit Platform : contient tout l’aspect « moteur » de JUnit. Utilisé pour exécuter les tests.
- JUnit Jupiter : combine une API et des mécanismes d’extension. Utilisé dans les tests unitaires.
- JUnit Vintage : fournit un moyen d’exécuter les tests unitaires existants initialement écrits pour JUnit 3 et 4
Ce découpage favorise ainsi l'intégration de JUnit dans les outils de développement au sens large du terme : IDE, build (gradle, maven) et intégration continue.
Les noms de packages ne sont bien sûr pas les mêmes que ceux de JUnit 4 afin de pouvoir combiner les tests Junit 4 et Junit 5. Cela nous permettra de migrer beaucoup plus sereinement nos tests et facilitera la réécritue de ceux-ci.
Junit 5 requiert bien évidement JAVA 8
Compatibilité IDE
IntelliJIDEA Version | BundledJUnit 5 Version |
2016.2 | M2 |
2016.3.1 | M3 |
2017.1.2 | M4 |
2017.2.1 | M5 |
2017.2.3 | RC2 |
2017.2.4 | 5.0.0 |
Pour Eclipse, la v5 de JUnit est compatible en beta dans la version 4.7 (Oxygen) à l'heure où j'écris cet article.
Concernant les autres IDE, rien n'a l'air de prévu pour le moment dans ce que j'ai pu lire.
Installation
Voici un exemple de configuration Gradle :
Changements
- Le package est org.junit.jupiter.api
- Les assertions se trouvent dans org.junit.jupiter.api.Assertions
- Les assumptions sont dans org.junit.jupiter.api.Assumptions
- @Before et @After deviennent respectivement @BeforeEach et @AfterEach
- @BeforeClass et @AfterClass deviennent respectivement @BeforeAll et @AfterAll
- @Ignore devient @Disabled
- @Category devient @Tag
- @RunWith est remplacé par @ExtendWith
- @Rule and @ClassRule sont remplacés par @ExtendWith
Assertions
En ce qui concerne les assertions, il y a eu un petit changement qui n'est pas anodin mais qui ne change pas grand chose : l'ordre des paramètres des méthodes a changé :
Nous retrouvons bien entendu les méthodes d'assert de base de Junit 4 à savoir : assertTrue, assertFalse, fail, assertEquals, assertNotEquals, assertArrayEquals, assertNotNull, assertNull, assertSame, assertNotSame et format.
Ces méthodes sont tout de même enrichies par rapport à la v4 (lambada entre autres).
Les nouvelles méthodes d'assert sont les suivantes : assertAll, assertThrows, assertTimeout, assertTimeoutPreemptively, assertIterableEquals et assertLinesMatch.
Voici deux petits exemples avec assertAll. Pour commencer une assertion groupée :
Il y a également la possibilité de faire des assertions dépendantes; le test dépendant n'est exécuté que si le parent réussi ce qui peut être fort pratique si nous souhaitons enchainer des tests entre eux.
Nouveautés
@DisplayName
L'annotation permet de "nommer" le test afin qu'il soit plus parlant et qu'ils apparaissent avec ce nom dans l'IDE au niveau des résultats de tests
Il y a toujours la possibilité de venir greffer des librairies de tests comme AssertJ ou Hamcrest.
Il existe un mécanisme d'assumptions qui permet de n’exécuter la suite du test que si une condition est vraie.
@Nested
Junit 5 introduit une notion de tests imbriqués. Il est donc désormais possible de regrouper des tests au sein d'une même classe.
@RepeatedTest
Vous avez aussi la notion d'effectuer une répétition qui vous permet de venir exécuter votre test X fois. Il y a la possibilité d'afficher des infos supplémentaires à l'exécution grâce à des paramètres liées à l'annot
Cela donnera ce genre de chose dans votre IDE
@ParameterizedTest
Cette notion vous permet de venir exécuter des tests via des jeux de données. Il est possible grâce à une annot supplémentaire de fournir en entrée des sources pour une méthode de test donnée :
- un tableau de strings "en dur"
- source CSV en dur ( @CsvSource({ "foo, 1", "bar, 2", "'baz, qux', 3" }) )
- enumeration source ( @EnumSource(value = TimeUnit.class, mode = MATCH_ALL, names = "^(M|N).+SECONDS$") )
- ...
- fichier CSV présent dans les resources de tests (cf. ci-dessous)
Vous obtenez donc ceci dans votre IDE préféré :
Il existe d'autres choses mais je vous laisse le soin de parcourir la doc JUnit 5 pour découvrir les autres nouveautés.
Configuration
Junit 5 vient avec la notion de sélecteurs et de filtres. Cela nous permet d'effectuer un paramétrage qui déclenchera des tests de façon différente suivants nos environnements.
Nous pourrons donc ainsi faciliter l'utilisation sur les différents outils et environnements que nous pouvons avoir sur nos projets.
Filtres
Les filtres sont directement intégrés à JunitPlateform et sont donc plus facilement configurables (plus directement en tout cas); nous avons juste à déclarer ce qui suit dans notre conf gradle :
Cette configuration aura pour effet d'exclure les tests (classe entière ou méthodes de tests) qui ont le tag 'slow'. Vous avez également la possibilité de venir désactiver les moteurs d’exécution également. Cela peut-être pratique pour n'exécuter que les tests junit 4 ou 5.
Vous avez également la possibilité de venir inclure des classes de tests par pattern matching (utilisé via plugin avant avec maven).
Sélecteurs
Extensions
Voici un exemple basique qui ne reflète pas forcement un cas usage réel mais qui nous permet d'assimiler la chose :
Nous constatons que grâce au mécanisme d'extension; dans ce cas précis nous venons initialiser nos mocks globaux mais également nos mocks locaux (injectés dans nos méthodes de tests) via l'extension (MockitoExtension) qui se chargera de tout ça.
Cela permet d'éviter leurs initialisations via une classe abstraite (pour le mock global) ou au sein même de nos tests; notre classe n'est ainsi pas alourdie et plus lisible.
Evolutions de JUnit
Les classes et les méthodes accessibles sont annotées via @API. La valeur d'utilisation de l'annotation peut être attribuée à l'une des cinq valeurs suivantes :
Cela nous permet donc d'avoir une idée globale de l'évolution des fonctionnalités que l'on utilisera dans nos tests.
Conclusion
Junit 5 apporte quand même une certaine souplesse par rapport au 4 et nous permet de faire des tests plus poussés grâce aux mécanismes qui ont pu être ajoutés. Il est surtout bien plus paramétrable ce qui facilitera nos exécutions de tests sur nos différents environnements.