Tests et TestNG
Fonctionnalités de TestNG
Regroupement de tests
TestNG nous permet de regrouper les tests par groupe. De plus un groupe de tests peut être inclus dans un autre groupe de tests. Voici un exemple de comment utiliser cela :
public class TestAvecGroupes {
@Test(groups = { "nonregression", "unit" })
public void testMethod1() {
}
@Test(groups = { "unit" })
public void testMethod2() {
}
}
Pour lancer cet exemple, nous pouvons écrire cela dans le fichier testng.xml:
<test name="TestAvecGroupes">
<groups>
<run>
<include name="nonregression">
</include></run>
</groups>
<classes>
<class name="univ.mlv.fr.xpose.tests.TestAvecGroupes">
</class></classes>
</test>
Dans ce fichier testng.xml nous avons fait le choix de ne lancer que les tests correspondants au groupe "nonregression".
Parallélisation du lancement des tests
TestNG nous permet également quelque chose de vraiment intéressant par rapport à JUnit, qui permet d'augmenter les performances. En effet testNG a mis à disposition des utilisateurs des méthodes pour lancer en paralléle plusieurs tests, grâce au procédé du multi-threading. Bien sûr comme je l'ai déjà dit précédemment, ce procédé est threadsafe, il n'y a pas de problème de concurrence généré par cette utilisation. Il existe deux manières de paralléliser du code de test:
- En utilisant le fichier testng.xml
Quand on veut faire cela par le biais du fichier testng.xml, il y a plusieurs solutions pour le faire:
- parallel ="methods"
<suite name="Suite1" parallel="methods" thread-count="6">
- parallel ="test"
<suite name="Suite2" parallel="tests" thread-count="6">
<suite name="Suite3" parallel="classes" thread-count="6">
@Test(threadPoolSize = 6, invocationCount = 10, timeOut = 10000)
public void testMethod() {}
Dans le bout de code précédent, nous déclarons un pool de thread de 6 threads et nous demandons que ce test s'exécute 10 fois. Pour éviter de rester bloqué quand un test échoue nous avons le timeout.
Une fois que nous avons lancé nos tests il est possible de regarder s'ils se sont bien lancés en paralléle grâce à cela:

Ici nous voyons qu'un seul et unique thread a lancé tous les tests (de manière séquencielle donc). Maintenant, si nous choisissons d'utiliser le parrallélisme cela donne: en écrivant cela dans le code de test:
@Test(dataProvider = "creerLivre", threadPoolSize = 3, invocationCount = 3, timeOut = 10000)
public void testAjoutNonRedondant(String n1, Livre l) {
Bibliotheque biblio = new Bibliotheque();
System.out.println("ajout de: " + l);
Assert.assertEquals(true, GestionBiblio.ajouterLivre(l, biblio));
}
Nous obtenons: 
Nous voyons bien que les tests testAjoutNonRedondant sont lancés par plusieurs threads
Génération dynamique de tests
TestNG nous permet également de générer dynamiquement des tests, pour illustrer cela, je vais reprendre un exemple fourni dans la documentation de testNG qui me semble très parlant:
Imaginez que vous vouliez tester une interface web N fois avec des valeurs différentes:
//factory
public class WebTestFactory {
@Factory
public Object[] createInstances() {
Object[] result = new Object[10];
for (int i = 0; i < 10; i++) {
result[i] = new WebTest(i * 10);
return result;
}
}
//class test utilsant la factory
public class WebTest {
private int m_numberOfTimes;
public WebTest(int numberOfTimes) {
m_numberOfTimes = numberOfTimes;
}
@Test
public void testServer() {
for (int i = 0; i < m_numberOfTimes; i++) {
// access the web page
}
}
}
Cet exemple nous montre très clairement qu'il nous sera beaucoup plus aisé de faire tous les tests voulus grâce à la factory plutôt qu'en les écrivant tous un par un.
Relancer les tests sortis en erreur
TestNG nous permet de choisir de ne relancer que les tests qui sont sortis en erreur, pour ce faire nous pouvons utiliser la ligne de commande de la manière suivante:
java -classpath testng.jar;%CLASSPATH% org.testng.TestNG -d test-outputs testng.xml
java -classpath testng.jar;%CLASSPATH% org.testng.TestNG -d test-outputs test-outputs\testng-failed.xml