Ch. 2 — Tests : politiques et outils
De la javadoc aux tests : niveaux CFTL, non-régression, white-box et black-box, mocks, DevOps et CI/CD — puis JUnit 5 : annotations, assertions et diagramme de cas d'utilisation.
La javadoc, avant les tests
La javadoc transforme SomeClass.java en SomeClass.html : les commentaires /** ... */
deviennent une documentation HTML navigable. Ils acceptent des balises HTML
(liens hypertextes, gras, italique) et des tags spécifiques — au niveau classe @version,
@author, @see, @since ; au niveau méthode @param, @return, @exception, @see,
@deprecated. La génération conserve l'arborescence des paquetages et tisse des liens
hypertextes entre classes :
javadoc yourProject/javaDocExample.java -d ../docsLa documentation est un artefact généré : elle se produit à la demande, elle ne se
versionne pas — le répertoire doc/ rejoindra le .gitignore (cf. chapitre 1).
Pourquoi tester ?
Règle fondamentale du cours : tout code non testé n'a aucune valeur. Mais le test a ses limites, résumées par E.W. Dijkstra dès 1972 (The Humble Programmer) : le test montre la présence de bugs, jamais leur absence. Fiabilité de 100 % impossible : la couverture ne peut généralement pas être totale, impossible de couvrir tous les cas, et les tests eux-mêmes peuvent contenir des bugs. La mise en œuvre a ses difficultés — réticences, temps de rédaction et de maintenance, véracité, répétabilité. Le test de non-régression détecte les régressions induites par un changement, pour limiter les anomalies relevées lors des tests d'acceptation. Dès qu'il faut rejouer tous les tests après chaque modification, l'automatisation s'impose : JUnit, TestNG, Cobertura, EMMA, Selenium, FitNesse.
Les quatre niveaux de test
Le Comité français du test logiciel (CFTL) identifie quatre niveaux : le test unitaire vérifie le fonctionnement d'une partie précise du programme ; le test d'intégration assemble et teste ensemble des modules indépendants ; suivent le test fonctionnel et le test d'acceptation (recette). S'y ajoutent des tests spécifiques : charge, stress, sécurité. Les ordres d'intégration — top-down, bottom-up, sandwich, big-bang — structurent cette phase. L'intégration continue, au sens simple : le programmeur détient toute l'application sur son poste et intègre tout au long du développement.
White-box, black-box et mocks
Le white-box testing cible la structure interne du programme : connaissance approfondie du code exigée, couplage général aux outils de couverture. Le black-box testing cible les fonctionnalités, à partir des seules spécifications demandées. Les mocks simulent un objet réel de façon contrôlée — base de données, service web : gain de temps considérable, simulation d'erreurs externes aisée, élimination des erreurs ne provenant pas du code.
DevOps et CI/CD
DevOps — contraction de development et operations — promeut l'automatisation et le suivi de toutes les étapes de la création d'un logiciel, du développement et des tests jusqu'au déploiement et à l'exploitation. Son cycle de vie compte neuf étapes — Manage, Plan, Create, Verify, Package, Release, Configure, Monitor, Secure — dont deux sont transversales ; l'écriture du code et l'ingénierie logicielle vivent dans Create.
L'intégration et la livraison continues (CI/CD) visent à accélérer le time-to-market, réduire les erreurs lors des livraisons et assurer la continuité de service. Cinq étapes, chacune outillée : planifier le développement (Jira, Confluence), compiler et intégrer le code (Git, Jenkins, Maven), tester (JUnit, NUnit), mesurer la qualité (PMD, SonarQube), gérer les livrables (Nexus, Docker Hub).
JUnit 5 en pratique
Le framework repose sur des annotations : @Test désigne la méthode d'essai ; @BeforeAll
ne s'invoque qu'une fois avant tous les tests, @BeforeEach avant chaque test ;
@AfterEach et @AfterAll ferment la marche. Par convention, l'ordre des paramètres d'une
assertion compte : d'abord la valeur attendue, ensuite l'appel testé.
La famille couvre les besoins courants : assertEquals/assertNotEquals (valeurs ou
objets, via equals), assertTrue/assertFalse, assertNull/assertNotNull,
assertSame/assertNotSame — deux références désignent-elles la même entité ?
@Test
public void RobotCanOnlyCarryOneBox() {
Robot robbie = new Robot();
Box b1 = new Box(10);
robbie.takeBox(b1);
assertSame(b1, robbie.getCarriedBox()); // b1 est bien la caisse portée
robbie.takeBox(new Box(5)); // exécution de la méthode testée
assertSame(b1, robbie.getCarriedBox()); // la caisse portée est toujours b1
}Pour un socle commun, @BeforeEach réinitialise attributs et instances avant chaque test —
le cours le montre avec BoxTest2. Bonnes pratiques : un nom de test significatif ;
un seul assert par test, donc une seule raison d'échouer ; maintenir le code de test
comme le code de production ; stocker les tests dans un paquetage dédié, au nom du
paquetage testé préfixé de test. Deux cas délicats : une méthode privée se teste via
les méthodes qui l'appellent, et une méthode sans type de retour n'est pas trivialement
testable.
Le diagramme de cas d'utilisation
Organiser des tests fonctionnels exige une vision de haut niveau : se focaliser sur les fonctionnalités sans se préoccuper de la technique, identifier rôles et fonctionnalités avec les parties prenantes, minimiser les incompréhensions. Le diagramme de cas d'utilisation (UML comportemental) répond à ce besoin : les acteurs — personnes ou systèmes —, le système auquel se rapportent les cas, les cas d'utilisation représentant une fonction. On distingue les acteurs primaires, qui initient la fonctionnalité, des acteurs secondaires, avec lesquels le système doit interagir pour la fournir — sur un site de vente, le Client est primaire pour « Commander », le ServicePaiement secondaire. Les acteurs sont des rôles : plusieurs acteurs peuvent correspondre à la même personne.
La couverture de code
Les outils de couverture (EMMA, Jacoco, JCoverage) déterminent quelles portions du code ne sont pas testées ou insuffisamment testées. Souvent intégrés à de gros frameworks : à éviter pour l'instant.
A retenir
- la javadoc se génère en HTML, elle ne se versionne pas ;
- tout code non testé n'a aucune valeur ; le test prouve la présence de bugs, pas leur absence ;
- quatre niveaux CFTL ; le non-régression rejoue à chaque changement ;
- white-box = structure interne, black-box = spécifications, mocks = simulateurs contrôlés ;
- CI/CD : planifier, compiler et intégrer, tester, mesurer la qualité, livrer ;
- JUnit 5 :
@Testet@BeforeEach…, valeur attendue en premier, un assert par test.
assertEquals vérifie l'égalité — via equals() pour les objets ; assertSame
que deux références désignent la même entité. Deux boxes de même poids sont
assertEquals mais assertNotSame.
Pour une seule raison d'échouer : la première assertion qui échoue masque les suivantes et rend le diagnostic ambigu.
@BeforeAll s'exécute une seule fois avant tous les tests, pour ce qui est coûteux
et partagé ; @BeforeEach avant chaque test, pour un état neuf et des essais
indépendants.
coursQU_02.pdf
R2.03 · Cours 2 — Les tests : politiques et outils · 28 diapositives
Chargement du document…
Dernière mise à jour le
Ch. 1 — Compilation et gestion de version
Compiler du Java à la main avec javac et java (-d, -cp, paquetages, jar) et comprendre le modèle Git : working copy, index, dépôt, commits, dépôt distant et .gitignore.
Ch. 3 — Qualité logicielle, Git avancé
Métriques de qualité (Déméter, complexité cyclomatique, Halstead), dette technique, SOLID, TDD, SCRUM et XP, PMD — puis Git avancé : tags, branches, merge, rebase et conflits.