Introduction des tests unitaires en Java – Mes premiers tests avec JUnit, pas à pas par exemple

Voici le premier cours sur ce blog, du coup, on va faire du simple et efficace, on va parler de tests unitaires via JUnit.

Ce cours servira d’introduction à d’autres cours sur les tests unitaires. Du coup, il y a rien de révolutionnaire sur cette page, on trouvera des connaissances assez basique facile à trouver sur le net. Je vais faire un cours basé sur plusieurs exemples détaillés afin d’expliquer mes points.

Les tests unitaires: Pourquoi ?

“Qui a cassé mon code ?” est une phrase bien trop souvent dite dans les équipes de dev’.
L’objectif principal des tests unitaires est de vérifier le comportement la fonction d’une classe donnée. Le code évolue avec le temps, ton collègue modifie une partie de ta classe. Le test permet de contrôler qu’il n’y a pas de régression sur les modifications, sans même regarder son code. Plus le code est testé, plus l’application est robuste.

Les asserts

Grace aux fonctionnalités asserts (assertThat, assertEquals, assertTrue, assertFalse, assertNull et assertNotNull) de JUnit, on va pouvoir vérifier la valeur retournée d’une fonction. Ainsi, on pourra créer différents scénarios pour cette fonction et vérifier si sa valeur de retour est conforme.

Voici un exemple simple, où l’on va mettre en place des tests:
public class Example1 {
	
	public String concat(String s1, String s2) {
		return s1 + s2;
	}
	
}
Nous allons tester notre classe Example1, et plus précisément la fonction concat, qui doit normalement concaténer deux chaines de caractères.
Nous allons commencer en créer une classe de test Example1_Test. Il est recommandé de séparer le code fonctionnel et le code de test, du coup les tests se trouvent dans leur propre classe.
package example1;
 
public class Example1_Test {
 
 
}
Il est conseiller de mettre cette classe de test dans le même package que sa classe à tester. Le nom de la classe de test doit faire aussi référence au nom de la classe à tester. Je rajoute le suffixe “_Test” ou bien “_Test_Should” a mes classes de tests.
Le test a toujours un but précis. Ainsi, on doit retrouver ce but dans son nommage. Le mot “should” se retrouve souvent dans la signature (classe ou fonction), afin de comprendre explicitement son but. Le test “devrait” retourner ça ou “devrait” utiliser ceci comme action … Je vous le conseille afin de construire vos tests.
Par convention, il est préférable de mettre les tests unitaires dans un dossier source différent du dossier source de l’application. (via les projets maven, le dossier source src/test/java est créé pour ceci)
Nous allons mettre en place notre premier test. Nous allons envoyer deux valeurs dans la fonction concat et nous allons tester la valeur de retour.
package example1;
 
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
 
import org.junit.Test;
 
public class Example1_Test {
 
	private Example1 exampleConcat = new Example1();
	private String value1 = "abc";
	private String value2 = "123";
 
	@Test
	public void concatFirstValueWithTheSecond() {
		assertThat(exampleConcat.concat(value1, value2), is("abc125"));
	}
}
La fonction concatFirstValueWithTheSecond de la classe Example1_Test sera considéré comme test, puisqu’elle possède l’annotation @Test (JUnit 4, Java 5 et +). Ainsi, on pourra lancer ce test via son IDE (par exemple pour eclipse, clic droit sur la classe ou la fonction -> “Run As” -> “JUnit Test”) ou via maven très facilement (la commande “maven test” de votre projet).
Dans ce test, on met une première valeur “abc” et une autre valeur “123”, puis on vérifie que la valeur de retour est bien la valeur “abc123”. La fonction assertThat considère le test en échec si son premier paramètre ne correspond pas au matcher se trouvant dans le second paramètre.
J’ai utilisé la fonction “is” se trouvant dans la bibliothèque hamcrest, qui permet de créer des matchers très facilement, cette bibliothèque est inclue dans JUnit. “is” permet de matcher avec la fonction “equals”.
Lancez votre test. Au moment de l’assertThat, le retour de la fonction concat ne retourne pas la même valeur que celle désirée (“abc125”). Le test échoue.
Changer la valeur du matcher de “abc125”  en “abc123” et relancer le test. Les valeurs sont identiques. Ainsi le test s’exécute avec succès.
Ok, la classe est partiellement testé. On va compléter notre classe de test afin d’augmenter la couverture de test de notre fonction concat. Voici deux autres tests que j’ai rajouté dans notre classe de test.
package example1;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;

import org.junit.Test;

public class Example1_Test {

	private Example1 exampleConcat = new Example1();
	private String value1 = "abc";
	private String value2 = "123";

	@Test
	public void concatTheFirstValueWithTheSecond() {
		assertThat(exampleConcat.concat(value1, value2), is("abc123"));
	}

	@Test
	public void returnEmptyWithNotFilledValues() {
		assertTrue(exampleConcat.concat("", "").isEmpty());
	}

	@Test
	public void returnStringObjet() {
		assertThat(exampleConcat.concat(value1, value2), instanceOf(String.class));
	}
}
Le test returnEmptyWithNotFilledValues ressemble au test précédent. Il utilise assertTrue au lieu de assertThat pour vérifier le comportement de la fonction concat. Cette fois-ci, pas de matcher. Afin que le test passe avec succès, la valeur se trouvant dans AssertTrue doit être un booléen de valeur true.
Le test returnStringObjet utilise assertThat, mais cette fois-ci, c’est le matcher qui change. Le matcher instanceOf va vérifier le type de classe à comparer. On va vérifier que concat retourne bien une chaîne de caractère. C’est très utile pour tester des Factory qui retournent des objets de différents types.

Conclusion

Vous pouvez retrouver l’exemple dans mon repository Git, partie JUnit.
Si vous avez des questions, n’hésitez pas à me les envoyer.

Leave a Reply

Your email address will not be published. Required fields are marked *