5 fonctionnalités de JUnit Jupiter à connaître

JUnit est le plus populaire des frameworks de tests unitaires pour Java. Cet article détaillera cinq fonctionnalités à connaître lorsque vous vous lancez dans le développement piloté par les tests (test driven développement ou TDD).

Les assertions

Toutes les assertions de JUnit Jupiter sont des méthodes statiques de la classe org.junit.jupiter.api.Assertions.

@DisplayName("Exemple d'assertions")
@Test
void assertionsTest() {
 assertEquals(2, 2);
 assertEquals(4, 4, "Message lorsque l'assertion a échouée");

 assertTrue(3 > 2);
 assertTrue(3 > 2, () -> "Evaluation paresseuse du message.");

 assertNull(null);
 assertNull("Message si la valeur n'est pas nulle", null);

 assertNotEquals(0, 1);
 assertNotEquals(3, 4, "Message lorsque l'assertion a échouée");
 assertFalse(3 < 2, () -> "Evaluation paresseuse du message.");

 assertNotNull("valueur non nulle");
 assertNotNull("Message si la valeur est nulle", "valueur non nulle");
}

Les tests d'exceptions

Bien tester les exceptions est quelque chose d'important pour développer des programmes robustes. Voici comment tester vos exceptions :

@DisplayName("Exemple de tests d'exceptions")
@Test
void exceptionTesting() {
 //Division par zéro
 assertThrows(ArithmeticException.class, () -> Math.floorDiv(2, 0), "Un message");

 //index trop grand
 assertThrows(IndexOutOfBoundsException.class, () -> "Mangue".substring(7, 8));

 //Valeur nulle
 String str = null;
 assertThrows(NullPointerException.class, () -> str.length());
}

Les tests avec paramètres

Types basiques

Vous pouvez tester avec des arguments basiques. Par exemple des chaines de caractères :

@DisplayName("Exemple de test avec paramètres")
@ParameterizedTest
@ValueSource(strings = {
   "Pomme",
   "Pêche",
   "Poire"
})
void fruitsCommenceParP(String fruit) {
   assertTrue(fruit.startsWith("P"));
}

Vous pouvez aussi avoir plusieurs arguments tant que le premier correspond à ValueSource.

/* ValueSource correspond au premier argument de la fonction */
@ParameterizedTest
@ValueSource(strings = {
 "Pomme",
 "Pêche",
 "Poire"
})
@DisplayName("Exemple de test avec information")
void avecAutresParametres(String fruit, TestInfo info) {
 System.out.println("Le fruit " + fruit + " a été passé en argument dans le test.");
 assertTrue(fruit.startsWith("P"));
}

CSV

Vous pouvez passer des arguments avec un format CSV.

@DisplayName("Exemple de test avec paramètres CSV")
@ParameterizedTest(name = "{index} => mot1={0}, mot2={1}")
@CsvSource({
   "Poire, Pomme",
   "Mangue, Melon"
})
void motsCommencentParLaMemeLettre(String mot1, String mot2) {
   assertEquals(mot1.substring(0, 1).toLowerCase(), mot2.substring(0, 1).toLowerCase());
}

Vous pouvez aussi passer des arguments avec un fichier CSV. C'est utile si vous voulez tester beaucoup d'arguments.

@DisplayName("Exemple de test avec paramètres dans un fichier CSV")
@ParameterizedTest(name = "{index} => mot1={0}, mot2={1}")
@CsvFileSource(resources = "fichier.csv")
void motsCommencentParLaMemeLettreFichierCSV(String mot1, String mot2) {
   assertEquals(mot1.substring(0, 1), mot2.substring(0, 1));
}

Enum

Vous pouvez passer en argument une énumération. Par exemple, avec l'énumération TimeUnit :

/* Toutes les unités */
@DisplayName("Exemple de test avec toutes les unités")
@ParameterizedTest
@EnumSource(TimeUnit.class)
void toutesLesEnums(TimeUnit unit) {
   System.out.println(unit.toString());
}

Ou bien avec une sélection :

/* Seulement les unités indiquées */
@DisplayName("Exemple de test avec seuelement quelques unités")
@ParameterizedTest
@EnumSource(value = TimeUnit.class, names = { "NANOSECONDS", "MICROSECONDS" })
void quelquesEnums(TimeUnit unit) {
   System.out.println(unit.toString());
}

Assume

Assume permet de faire une supposition. Si la supposition est fausse, le test s'arrête. Si la supposition est vraie, le test continu.

@Test
public void assumeFrance() {
   Locale local = Locale.getDefault();
   assumeTrue(local.equals(Locale.FRANCE));
   System.out.println("Exécute le test si la langue du système est le français");
}
    
@Test
public void assumeCanadaFrench() {
   Locale local = Locale.getDefault();
   assumeTrue(local.equals(Locale.CANADA_FRENCH));
   System.out.println("Exécute le test si la langue du système est le québécois");
}
    

Exécution de tests conditionnels

Exécuter un test seulement sous Linux :

@Test
@EnabledOnOs(value = OS.LINUX)
public void executeLeTestSousLinux() {
   System.out.println("Exécute le test sous Linux");
}

Exécuter un test seulement sous Java 10 :

@Test
@EnabledOnJre(value = JRE.JAVA_10)
public void executeLeTestSiJava10() {
   System.out.println("Exécute le test si le JRE est sous Java 10");
}

Exécuter un test seulement avec les architectures 64 bits:

@Test
@EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*")
void seulementPour64Bits() {
   System.out.println("Exécute le test si l'OS est un 64 bits");
}

Conclusion

JUnit Jupiter offre encore une multitude de fonctionnalités. Vous pouvez consulter la documentation de Junit Jupiter pour en savoir plus. Cependant, il ne faut pas oublier que les tests doivent rester simples. Si vous faites des tests trop complexes, vous risquez d'introduire des bugs dans vos tests.

N'oubliez pas d'utiliser les bonnes méthodes d'assertions au bon moment. assertEquals sera plus lisible qu'un assertTrue(str.equals("Test")) par exemple. Il ne faut pas oublier de biens nommer les méthodes de test. Généralement on commence par le mot "devrait" ou "should" en anglais. Dans tous les cas le nom du test devrait décrire ce que vous êtes en train de tester. Vous pouvez utiliser l'annotation DisplayName pour plus de lisibilité.

Vidéo

Voir la vidéo sur les 5 fonctionnalités de JUnit à connaître.

Commentaires