Les tests apportent beaucoup de quiétude aux développeurs lorsqu'ils modifient le code car ils savent que de nombreux bugs seront détectés automatiquement. Durant le développement, si un bug est corrigé alors qu'il n'était pas couvert par une méthode de test, il faut écrire une nouvelle méthode de test pour le détecter à l'avenir s'il est réintroduit par une future modification du code.
Lisez la suite si vous voulez avoir des exemples concrets d'écriture de test.
Il faut commencer par ajouter 2 dépendances pour JUnit version 5 dans pom.xml, si ça n'est pas déjà le cas (le modèle, archétype dans le jargon Maven, utilisé pour créer une application Web peut changer suivant les versions de NetBeans). Choisissez les dernières versions de ces dépendances (5.9.1 au moment où ces lignes sont écrites) :
<dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.10.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.10.0</version> </dependency>
Faites un clean and build du projet pour charger les dépendances.
Pour suivre les conventions de Maven, les tests doivent être écrits dans le répertoire src/test/java du projet.
NetBeans va vous aider pour créer les tests.
Si vous voulez créer des tests sur la classe CompteBancaire
, clic sur la classe puis menu Tools > Create/Update Tests.
Une fenêtre pop-up s'affiche. Vous devez commencer par décocher la case "Integration Tests" car vous voulez générer une classe de test unitaire.
La fenêtre vous propose de créer une classe CompteBancaireTest
dans le même paquetage que la classe CompteBancaire
(mais à un autre endroit, sous src/test/java
et pas sous src/main/java
, selon les conventions de Maven). Par défaut le plugin Surefire de Maven qui s'occupe des tests ne considère que les classes de tests dont le nom se termine par "Test".
Elle propose de tester toutes les méthodes public
, protected
et "package private" (sans modificateur de visibilité). Elle propose de faire générer des méthodes qui seront exécutées avant (@BeforeEach
) ou après chaque test (@AfterEach
) pour préparer l'environnement de chaque test et faire le ménage ensuite, des méthodes qui seront exécutées avant (@BeforeAll
) ou après(@AfterAll
) tous les tests des méthodes de la classe. Vous pouvez décocher les cases Prtoected, Package Private, Test Initialize, Test Finalizer, Test Class Initializer, Test Class Finalizer car vous allez juste tester la méthode testDeposer()
.
Clic sur le bouton OK.
Le code de la classe de test générée contient des méthodes qui testent toutes les méthodes de la classe CompteBancaire
. Une classe de test est une classe qui contient au moins une méthode de test. Une méthode de test est annotée par @Test
(il existe aussi d'autres annotations pour les méthodes de test, que nous ne verrons pas dans cette courte introduction).
Vous pouvez étudier ces méthodes pour comprendre comment elles fonctionnent. Elles sont toutes écrites sur le même modèle. Par exemple
@Test public void testDeposer() { System.out.println("deposer"); int montant = 0; CompteBancaire instance = new CompteBancaire(); instance.deposer(montant); // TODO review the generated test code and remove the default call to fail. fail("The test case is a prototype."); }
Cette méthode de test sera exécutée quand un test de la méthode deposer
sera lancé.
Le code généré automatiquement par NetBeans crée une instance de CompteBancaire
puis utilise la méthode deposer
.
A la fin, la méthode fail
affiche un message pour dire que le test a échoué. Il faut évidemment modifier le code généré automatiquement pour vraiment tester si la méthode deposer
fonctionne correctement. Par exemple, le code peut être remplacé par un code qui déposer un montant de 100 et teste ensuite si le solde est bien 100. La méthode assertEquals
vérifie que le solde est bien égal à 100. Dans le cas contraire le message d'erreur passé en dernier paramètres sera affiché :
@Test public void testDeposer() { System.out.println("deposer"); int montant = 100; CompteBancaire instance = new CompteBancaire(); instance.deposer(montant); assertEquals(instance.getSolde(), montant, "Mauvais calcul du solde après un dépôt"); }
Comme la méthode getSolde()
est tellement simple qu'elle ne peut contenir d'erreur, cette méthode teste bien de façon unitaire la méthode deposer
.
Supprimez les autres méthodes de test (il faudrait aussi toutes les modifier).
Nous voulons aussi tester le constructeur qui prend des paramètres. NetBeans n'a pas généré de code pour cela. Voici un exemple de code de test :
@Test public void testConstructor() { int montant = 100; CompteBancaire instance = new CompteBancaire("toto", montant); assertEquals(instance.getNom(), "toto", "Nom titulaire compte mal enregistré dans l'instance"); assertEquals(instance.getSolde(), montant, "Montant compte mal enregistré dans l'instance"); }
Pour lancer les tests, clic droit sur CompteBancaire > Test File. La ligne suivante doit apparaître dans la fenêtre "Output -Test(CompteBancaire)" en bas de NetBeans :
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
Les tests de toutes les classes de l'application seront aussi lancés automatiquement lors des builds de l'application (cycle de vie standard de Maven). Si un des tests n'est pas satisfait, le build de l'application ne se poursuit pas après les tests et l'exécutable ne sera pas construit (fichier war pour cette application).
Pour voir ce qui se passe si un test ne fonctionne pas, modifiez testConstructor
pour qu'une assertion ne soit pas vérifiée et lancez un "Clean and Build" de l'application. Dans l'onglet "Output" vous devriez alors voir, par exemple si vous avez remplacé "toto" par "totoa" dans le assertEquals
:
------------------------------------------------------- T E S T S ------------------------------------------------------- Running xxx.yyy.tpbanque.entity.CompteBancaireTest deposer Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.064 sec <<< FAILURE! xxx.yyy.tpbanque.entities.CompteBancaireTest.testConstructor() Time elapsed: 0.025 sec <<< FAILURE! org.opentest4j.AssertionFailedError: expected:but was: at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55) at org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62) at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182) at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177) at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1124) at xxx.yyy.tpbanque.entity.CompteBancaireTest.testConstructor(CompteBancaireTest.java:16) Results : Failed tests: xxx.yyy.tpbanque.entity.CompteBancaireTest.testConstructor(): Nom titulaire compte mal enregistré dans l'instance ==> expected: <toto> but was: <totoa Tests run: 2, Failures: 1, Errors: 0, Skipped: 0 ------------------------------------------------------------------------ BUILD FAILURE ------------------------------------------------------------------------ Total time: 5.882 s Finished at: 2021-04-12T14:55:22+02:00 ------------------------------------------------------------------------ Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test (default-test) on project TPBanque: There are test failures.
Vous pouvez écrire d'autres tests pour des méthodes de l'application.
Par exemple, si vous faites les parties optionnelles et si vous écrivez et utilisez CompteException
, écrivez un test qui vérifient que l'exception est levée si on retire un montant supérieur au solde. Vérifiez aussi que l'exception n'est pas levée si on retire un montant égal au solde. Aide.