Introduction au test logiciel/Intégration dans le processus de développement
Jusqu'ici, nous avons vu comment vous pouviez développer dans votre coin des tests portant sur le code que vous écrivez. Cependant, le développement d'un logiciel est un processus plus global : voyons comment les tests s'intègre avec les autres tâches à effectuer et comment on peut travailler en équipe.
Développer avec les tests
modifierBien que ce ne soit pas systématique, la pratique courante est que le code et les tests sont écrits par la même personne.
Écrire des tests prend du temps qu'on pourrait passer à écrire du code apportant de nouvelles fonctionnalités. Cela peut paraître frustrant, mais il faut renoncer à la course à la fonctionnalité pour préférer avancer plus lentement mais plus sûrement. En particulier, on est tenté de négliger l'écriture des tests après plusieurs semaines passées sur un projet, surtout en phase de bouclage où « on a plus le temps pour ça ». Appliquer une démarche de tests rigoureuse tout au long du projet permet de modifier le code aussi sereinement en fin de projet qu'au début (les tests assurant la non-régression). La solution réside dans l'équilibre, c'est en fonction des contraintes du projet et du sentiment de maîtrise des développeurs qu'il convient de placer le curseur entre deux extrêmes qu'il faut éviter : « pas de temps pour les tests » et « 100 % de couverture, peu importe le temps que ça prendra ! ».
Après plusieurs mois de pratique, un développeur peut se demander « À quoi bon écrire des tests, on ne trouve jamais de bogues ». On peut le comprendre étant donné qu'après la mise en place d'une démarche des tests, les bogues se raréfient : on peut alors avoir l'impression que les tests ne servent à rien. Ce serait se tromper. Pour s'en convaincre, il suffit d'abandonner les tests pour voir ressurgir des bogues à retardement.
Les tests et la gestion de version
modifierSi vous travaillez à plusieurs sur le développement du projet, vous utilisez probablement un outil de gestion de version de code-source (comme CVS, Git ou Subversion). Vous pouvez l'utiliser pour stocker vos classes de tests aux côtés des classes.
Vous pouvez adopter des règles strictes :
- Ne jamais envoyer une classe qui n'est pas accompagnée d'un test
- Toujours faire passer les tests lorsqu'on récupère un projet
- Avant de faire un commit :
- Relancer tous les tests
- Mettre à jour le code
- Repasser tous les tests
- Faire le commit
Le développement piloté par les tests
modifierLe développement piloté par les tests (ou « Test-Driven Development » ou « TDD ») est une pratique souvent utilisée dans les méthodes agiles (on trouve son origine dans l'extreme programming). Elle consiste à développer l'application selon le cycle suivant :
- Écrire les tests
- Vérifier que ceux-ci ne passent pas
- Écrire le code manquant
- Vérifier que le test passe
- Remanier le code
1. Écrire les tests
modifierDans le développement piloté par les tests, les tests sont écrit avant le code. Il faut donc commencer par écrire un test ou un petit ensemble de tests qui représente les nouvelles fonctionnalités qu'on va implémenter durant le cycle.
Il faut pour cela se baser sur la spécification, les cas d'utilisation ou les user stories. Écrire les tests d'abord permet au développeur de voir vraiment le comportement qui est attendu avant de toucher au code.
2. Vérifier que les nouveaux tests échouent
modifierIl est important de lancer les tests pour s'assurer que les autres passent toujours et que les nouveaux tests ne passe pas. Dans le cas contraire, deux possibilités :
- Le test n'est pas bon
- La fonctionnalité est déjà implémentée. Cela peut arriver étant donné qu'un développeur zélé peut, lorsqu'il touche une partie du code, ajouter dans la foulée un petit peu de plus de fonctionnalité que prévu.
Toutefois, si ce dernier cas se présente plusieurs fois, il faut se poser des questions sur la gestion du projet. Les tâches ont-elles bien été réparties ?
3. Écrire le code
modifierIl est important d'essayer de n'écrire strictement que le code nécessaire au passage du test, pas plus. Vous pouvez relancer le test écrit à l'étape 1 autant de fois que nécessaire. Peu importe si le code n'est pas élégant pour l'instant tant qu'il permet de passer le test.
4. Vérifier que tous les tests passent
modifierC'est le moment de vérifier que tous les tests passent, ceci afin de vérifier qu'avec les modifications faites on n'a pas créé de régressions dans le code.
5. Remanier le code
modifierEnfin, refactorisez le code pour améliorer la conception tout en vérifiant que les tests passent toujours.
Intégrer les tests à la construction automatique du projet
modifierAvec Ant
modifierSi vous utilisez Ant pour construire vos projets, il existe la tâche junit
. Attention, elle dépend des fichiers junit.jar et ant-junit.jar qu'il faut télécharger et indiquer dans le fichier build.xml. Référez vous à la documentation de la tâche junit
dans la documentation officielle de Ant.
Avec Maven
modifierSi vous utilisez maven pour construire et gérer les dépendances de votre projet. Vous pouvez lui demander de faire passer tous les tests.
mvn test
Maven intègre une convention pour placer les tests dans l'arborescence du projet. Vous pouvez déclarer JUnit et vos autres outils comme des dépendances. Vous pouvez également intégrer à la génération du site, la génération et la publication des rapports sur le respect de conventions et la couverture.
Gardez l'essentiel des tests rapidement exécutables
modifierQuoi qu'il en soit, la construction du projet doit rester légère, et dérouler les tests ne doit pas prendre plus de quelques minutes. Le risque, en laissant le temps de construction s'allonger indéfiniment au fur et à mesure que les tests s'accumulent, est de lasser les développeurs qui seront tentés de sauter la phase de test de la construction.
Une bonne pratique consiste à laisser les tests unitaires dans la construction du projet et à ignorer les tests d'intégration dans le build par défaut. Une petite option (un profil Maven) permettant d'activer le passage des tests d'intégration. Le serveur d'intégration, lui, pourra construire systématiquement en repassant tous les tests.
Profitez des ressources du serveur d'intégration continue
modifierSi vous faites de l'intégration continue, vous utilisez un système de gestion de version et vous avez sûrement un serveur chargé de construire régulièrement le projet. Vous pouvez faire en sorte que chaque construction rejoue l'ensemble des tests pour vérifier que tout va bien. Cette construction automatique régulière peut donner lieu à la génération de rapports. Votre serveur d'intégration peut donc vous permettre de suivre l'évolution des métriques et de la complexité du projet.
Coupler le serveur d'intégration continu avec un outils de panneau de contrôle tel que Sonar vous permettra de suivre l'évolution du succès des tests et de la couverture du code en fonction du temps et de l'évolution de la complexité de l'application. Sonar permet de voir où se trouvent les portions de codes les moins testées.
Rapprocher les tests de l'utilisateur
modifierSi les méthodes agiles recommandent les tests, elle recommandent également d'intégrer l'utilisateur au processus de développement afin que les réalisations des développeurs collent au plus près des véritables attentes qu'on peut avoir du logiciel.
Les tests sont d'abord une discipline technique mais nous allons voir que par différentes façon, nous pouvons rapprocher ces travaux des utilisateurs. Les trois approches suivantes tentent de mêler les tests avec la documentation utilisateur (le cas doctest) ou avec les spécifications du logiciel (Fit et BDD). L'objectif est d'avoir des tests écrit dans un langage compréhensible par l'utilisateur, voire de permettre à l'utilisateur d'écrire les tests lui-même sous forme de tableau de valeurs dans un tableur (Fit) ou en langage simili-naturel (BDD). Idéalement, ces technologies permettrait de confronter l'implémentation du logiciel aux spécifications attendues, décrites en langue naturelle : on peut parler de spécification exécutable (anglais executable spec).
Mêler tests et documentation, l'approche doctest
modifierdoctest est un outil livré avec Python qui permet, dans une documentation au format texte brut ou rST, d'ajouter des lignes qui permettent de vérifier ce qui vient d'être dit. L'exemple suivant montre un fichier texte d'exemple, il pourrait s'agir d'un fichier README.txt
.
======================
Demonstration doctests
======================
This is just an example of what a README text looks like that can be used with
the doctest.DocFileSuite() function from Python's doctest module.
Normally, the README file would explain the API of the module, like this:
>>> a = 1
>>> b = 2
>>> a + b
3
Notice, that we just demonstrated how to add two numbers in Python, and
what the result will look like.
En lisant ce fichier, doctest va interpréter les lignes préfixées par >>> et vérifier que ce qui est retourné par l'évaluation de l'expression correspond à ce qui est écrit (ici, doctest va vérifier que l'évaluation de a + b renvoie bien 3).
Des tests orientés données, l'approche Fit
modifierWard Cunningham propose dans son outil « fit » de rédiger les tests de validation dans un document, sans code. Son outil comprend un lanceur de test mais aussi un wiki embarqué, accessible via une interface Web. Dans ce wiki, les utilisateurs peuvent entrer, dans des tableaux, les jeux de données à fournir en entrée ainsi que les résultats attendus en sortie. Une autre possibilité, donnée aux utilisateurs, est d'entrer les jeux de données dans un tableur.
- Java
- Fit, FitNesse (avec trinidad), Concordion
- PHP
- phpfit
Des tests fonctionnels en phase avec les attentes de l'utilisateur, l'approche BDD
modifierC'est en essayant d'enseigner l'approche TDD que Dan North s'est rendu compte que la plupart des développeurs acceptent volontiers d'écrire les tests avant le code mais se contentent de percevoir cette technique comme une façon de tester en même temps qu'on développe, sans percevoir ce qu'il s'agit en fait d'une méthode de développement. Pour faciliter cette compréhension de TDD, Dan North a étendu les notions de bases pour former Behavior Driven Development, une méthode sensée apporter aux développeurs tous les bénéfices d'une véritable approche de TDD.
Des tests bien nommés
modifierNotion de « Comportement »
modifierLes attentes utilisateurs sont aussi des comportements
modifierFrameworks de BDD
modifier- Groovy
- GSpec, Spock, easyb
- Java
- Cucumber-JVM, un port officiel de Cucumber pour les différents langages de la JVM, Instinct, JBee, JBehave, JDave, Robot Framework, Narrative
- JavaScript
- Jasmine
- PHP
- behat
- Python
- Freshen, Lettuce, Pyccuracy, Pyhistorian, PyCukes
- Ruby
- RSpec, Cucumber
- Scala
- ScalaTest, specs
Pour aller plus loin
modifierTests de non-régression
modifierIl s'agit de tests qui visent à assurer la non-régression d'une application. C'est à dire qu'une modification apportée à l'application ne rend pas erronés les comportements d'une application qui fonctionnaient avant la modification.
« Beta test »
modifierLe beta-test consiste à fournir une version quasi-finale de l'application (dite « version Beta ») à un large échantillon d'utilisateurs finaux. Ceci afin qu'ils rapportent les derniers bogues résiduels ou dans le cas d'une interface graphique, quelques améliorations ergonomique. La version livrée est estampillée « Beta » afin que les utilisateurs soient conscient qu'il ne s'agit pas le version finale et que le version présentée peut encore contenir des erreurs.
On parle de bêta ouverte ou de bêta fermée selon que cette version du logicielle soit accessible à tous les utilisateurs potentiels ou seulement à un groupe restreint.