Test et assurance qualité
Contexte
Tester un système une fois qu’il a été implémenté n’est pas une option pour les entreprises qui veulent produire des logiciels de qualité. Le risque de régression est quasiment proportionnel à la taille du système, pondéré par sa complexité, par l’expérience des développeurs, par les facteurs techniques. De plus, la pratique du test, qu’il soit automatisé ou non, est une aide au développement et à la conception. Les méthodes agiles ont contribué à l’essor du test unitaire, de même que les frameworks de test automatisé, JUnit en tête.
Tester veut dire évaluer les effets d’un changement. La conclusion est binaire : accepter ou rejeter.
1. Utilisation
a. Agilité
Le Test Driven Development (TDD) est la discipline phare de l’Extreme Programming. On peut affirmer qu’elle est autant décriée que vénérée. Personne ne remet en cause la nécessité des tests automatisés, la polémique se situant au niveau du pilotage par les tests plutôt que par le design. Les adeptes du TDD considèrent implicitement qu’une modélisation en amont n’est pas nécessaire car le design émergera naturellement par la refactorisation.
Le processus est simple : avant de coder une classe, on commence par coder les tests.
On s’arrange pour que chacune des opérations de la classe soit initialement couverte par un test unitaire qui échoue. Ensuite, on implémente les tests comme si la classe était opérationnelle. Ce faisant, on modifie le design de la classe pour qu’elle corresponde à l’usage des tests. Lorsqu’on considère que les tests sont suffisamment étoffés pour garantir une exploitation concrète de la classe, on implémente les opérations de celle-ci jusqu’à ce que l’intégralité des tests passe.
Figure 6.1 : Workflow du TDD (source : Wikipédia)
L’un des intérêts majeurs du TDD est que le développeur doit comprendre, donc analyser, la fonctionnalité - en se concentrant sur les exigences, ou user stories - qu’il doit implémenter pour écrire un test pertinent....
Outils
1. JUnit
JUnit est un framework de test unitaire pour le langage Java, inventé par Kent Beck and Erich Gamma. Cette bibliothèque a été ensuite déclinée pour la grande majorité des langages de programmation (une bonne trentaine actuellement). Son avènement a contribué à l’adoption massive du test unitaire. Il est même plutôt fréquent de voir un novice à peine initié aux méthodes de test unitaire devenir test infected (accro au test), et de le voir prendre un plaisir évident à cette pratique.
Ce framework rassemble les test case relatifs au sein d’une test suite qui sera exécutée par un test runner. Cela permet de produire des batteries de tests automatisés, autovérifiables et qui peuvent s’exécuter simultanément et indépendamment les uns des autres. Il est tellement bien intégré aux environnements de développement modernes qu’on peut l’utiliser de façon native et le développeur a immédiatement le plaisir de voir la couleur de sa barre de progression tendre vers le vert.
Figure 6.4 : Résultats d’une batterie de tests automatisés dans Netbeans
2. JMeter
JMeter est un outil open source, 100 % Java, qui permet de mesurer la capacité de montée en charge d’une application orientée réseau....
Techniques
Le test unitaire fait partie intégrante de l’activité de développement. Aussi doit-on y apporter autant de soin qu’à l’écriture du code lui-même. Nous allons présenter dans cette partie un certain nombre de techniques de test classiques.
1. Boîte noire
Tester en boîte noire signifie n’utiliser que les fonctions de la classe pour tester celle-ci, et donc ne pas avoir connaissance a priori de son implémentation ni de ses membres privés. Par exemple, pour un objet d’accès aux données (DAO) qui dispose des opérations classiques de CRUD (Create Read Update Delete), on ne pourra tester la fonction de création ou de suppression qu’avec la fonction de recherche.
L’avantage immédiat qu’on peut retirer de cette approche est qu’elle impose une interface exhaustive pour l’objet à tester et donc consolide le design. A contrario, cela obligera peut-être à développer des opérations inutiles.
En revanche, on ne peut pas tester de cette manière les membres private ou protected.
a. Exemple
L’exemple suivant illustre un test en boîte noire de la fonction delete :
-
On s’assure d’abord que l’objet Customer n’est pas présent dans le système (à l’aide de la fonction find).
-
On utilise la fonction create pour le sérialiser.
-
On s’assure qu’il existe bien.
-
On appelle la fonction delete pour supprimer l’objet du système.
-
On appelle une troisième fois find pour vérifier que la suppression est effective.
public class CustomerDaoTest {
protected CustomerDao dao = null;
@Before
public void setUp() {
if (dao != null) {
dao.clear();
}
}
@Test
public void testDelete() throws CustomerException {
System.out.println("delete");
if (dao != null) {
String email = "tom@eni.fr";
...