Souvent sous-évalué et jugé peu digne d’intérêt par les développeurs, le test n’en est pas moins un maillon crucial de l’ingénierie logicielle, et un pilier fondamental sans lequel aucun logiciel peut être mis sur le marché avec la qualité nécessaire. L’objectif de cet article est de vulgariser les dimensions majeures du test logiciel et de donner un retour d’expérience des meilleures pratiques telles que nous les percevons chez SoftFluent.
Dans cet article, nous verrons :
- Un investissement souvent insuffisant dans la qualité
- Les différents niveaux de tests
- Le différentes natures de tests
- Favoriser la détection précoce des anomalies
- L’évolution vers les méthodes agiles
- 10 conseils à retenir
Un investissement souvent insuffisant dans la qualité
Le test est une discipline vaste qui permet de s’assurer de la qualité des logiciels. Cette qualité comprend différentes dimensions que l’on peut regrouper dans les trois catégories suivantes : les fonctionnalités, l’ingénierie et l’adaptabilité.
En France, ce phénomène est probablement accru par le poids important des sociétés de services et des développements spécifiques. Leur importance relative est plus forte qu’ailleurs, en partie pour des raisons culturelles, et par conséquent, la culture des logiciels “ packagés ” est plus faible. Les sociétés de services ont en effet une sensibilité moindre que les éditeurs de logiciels à la qualité, car l’impact d’une correction est souvent limité. A l’inverse, un éditeur de logiciel doit investir sur la qualification de son logiciel en amont, sous peine de payer très cher les multiples déploiements de son produit.
Dans des sociétés comme Microsoft, où les logiciels sont déployés par dizaines de millions d’exemplaires, certaines équipes comportent jusqu’à deux testeurs par développeur !
Les différents niveaux de tests
Tout d’abord, notons que les tests logiciels se font en général à plusieurs niveaux. On distingue potentiellement quatre niveaux de tests :
- Les tests unitaires, qui sont menés par le développeur lui-même, et qui consistent à vérifier la bonne exécution des fonctions dont il a la charge. Ces fonctions sont testées de manière indépendante, souvent avec des données réduites. Il est souhaitable de définir très tôt des jeux de tests représentatifs, car le développeur pourra réaliser les tests unitaires sur cette base et la qualité en sera améliorée.
- Les tests d’intégration, qui sont menés par un testeur dédié, au sein de l’équipe de développement ou d’une équipe qualité travaillant en coopération étroite. La particularité de ces tests est que ceux-ci visent à tester la mise en commun de plusieurs composants et l’enchaînement de processus complets au-delà des simples fonctions unitaires. On parle parfois de tests en boîte blanche, dans la mesure où l’on est amené à regarder les relations entre les composants pour vérifier leur bonne coopération. Là encore, la disponibilité de jeux de tests tôt dans le cycle est un facteur important d’efficacité.
- Les tests du système complet ou la qualification, qui consistent à dérouler des scénarios complets, représentant les cas d’utilisation du logiciel, sans se préoccuper de l’implémentation ou des composants sous-jacents. On est alors dans une logique de boîte noire, et il est fortement recommandé que l’équipe qui réalise ces tests soit distincte de l’équipe de développement. Elle peut même parfois être mise en “ off-shore ” ce qui a le mérite de nécessiter un formalisme assez détaillé, et de pousser à une bonne description de l’ensemble des scénarios d’utilisation. Lors de l’évolution du système, on rejouera ces scénarios afin de valider la non-régression.
- Les tests d’acceptation, menés avec des utilisateurs pilotes, afin de valider l’adéquation du logiciel au métier et sa facilité d’adoption par ceux qui devront l’utiliser régulièrement. De la même manière, associer très tôt les utilisateurs à une première portion du logiciel permettra de connaître les critères d’acceptation par les utilisateurs, et, au besoin, d’ajuster certains choix par exemple ergonomiques.
Notre conviction sur les tests unitaires, d’intégration et du système, est que pour des logiciels métiers, il convient d’automatiser au maximum ces tests. Un test déroulé manuellement est une charge. Un test consolidé dans un script re-jouable à l’infini est un investissement. L’automatisation des tests unitaires et de certains tests d’intégration permet d’en extraire des sous-ensembles re-jouables lors de la génération elle-même automatisée du système.
Par ailleurs les artefacts de tests comme le code des tests unitaires, leurs fichiers de configuration ou les jeux de données, participent à la documentation du logiciel nécessaire pour sa maintenance et comme exemples d’utilisation des interfaces publiques (APIs). Ceci est particulièrement important dans les systèmes exposant certaines fonctionnalités sous formes de services, ou s’intégrant dans d’autres systèmes.
Les différentes natures de tests
Par ailleurs, on distingue des tests différents par leur nature :
- Les tests fonctionnels valident le bon comportement du logiciel en matière de service rendu. Ces tests sont souvent ceux décrits en détail dans les scénarios et sur lesquels l’essentiel de l’investissement est fait, par analogie aux spécifications qui décrivent souvent en détail la fonction à remplir. Notre recommandation sur le sujet rejoint les points évoqués ci-dessus. Ecrire les scénarios très tôt est fortement souhaitable, car cela valide la bonne analyse fonctionnelle, tout en donnant de la matière au développeur pour ses propres tests unitaires. Mais mettre l’exclusivité de l’effort sur ces tests est une erreur encore fréquente.
- Les tests de compatibilité de plate-forme comprennent au minimum des tests d’installation et de bon fonctionnement sur des environnements ciblés (système d’exploitation, base de données… ), voire pour les éditeurs des tests plus poussés détectant les problèmes potentiels avant certification pour une plate-forme donnée. Ils permettent de détecter le respect des bonnes pratiques telles que l’utilisation de répertoires virtuels, l’exécution sans droits d’administration, la désinstallation, la localisation des ressources etc. Les postes des développeurs ne doivent pas être confondus avec l’environnement d’exécution cible.
- Les tests de robustesse visent à tester le logiciel dans des conditions dégradées ou aux limites. Ils sont rarement menés de manière systématique, alors qu’ils ne sont pas compliqués à mettre en œuvre : débranchement d’un câble, arrêt brutal d’une machine… Il est important de savoir comment le logiciel réagit en ces circonstances et de définir le scénario de reprise. Faire l’impasse permet de gagner (à peine) un peu de temps à court terme, mais laisse planer un risque dont les conséquences financières sont souvent impossibles à évaluer. Il est évident que l’utilisateur sera tôt ou tard confronté à une panne réseau, alors autant prévoir de suite le comportement du logiciel et documenter le symptôme.
- Les tests de performance sont souvent menés en fin de projet. Les facteurs influant sur la performance étant nombreux, il est risqué de tirer des conclusions hâtives sur des tests partiels en l’absence de volumes représentatifs et de présence de l’ensemble des conditions d’exécution. Cependant les développeurs peuvent très bien tester le comportement de certains services unitaires tôt dans le cycle lorsque ceux-ci présentent un risque de performance. De plus, l’expérience prouve que les résultats de ces tests doivent surtout être précisément documentés afin de formaliser les conditions dans lesquelles les mesures ont été prises et les conclusions tirées doivent être analysées au vu de compteurs significatifs : consommation CPU, évolution de l’utilisation mémoire, nombre de requêtes par seconde, flux d’entrée/sortie…
- Les tests de montée en charge doivent être distingués des tests de performance. Une application peut être performante mais limitée dans sa capacité à soutenir un nombre croissant d’utilisateurs (ou tout autre paramètre). Un système logiciel, particulièrement s’il est destiné à l’Internet, doit être conçu pour pouvoir monter en charge de manière illimitée par simple ajout de matériel. Des tests doivent être menés en ce sens, avec des outils permettant de simuler de nombreux clients simultanés.
- Les tests d’ergonomie sont rarement menés car ils nécessitent d’associer des utilisateurs finaux. Pourtant, ils peuvent être un facteur très important de qualité réelle et perçue, en améliorant le confort d’utilisation des logiciels. Ces tests incluent tout autant la facilité d’utilisation (le « Feel ») que l’apparence visuelle (le « Look »).
- Les tests d’interface graphique sont réalisés à la fin du cycle de développement et permettent de détecter les régressions. Chez SoftFluent, nous avons créé notre propre outil ‘SoftFluent Automation’ pour simplifier ce travail.
Favoriser la détection précoce des anomalies
Le lecteur aura compris au travers des différents commentaires des paragraphes qui précèdent que chez SoftFluent, nous sommes plus proches des méthodes agiles que cascadées, et nous privilégions tout ce qui permet de disposer de cycles courts, pour le test comme pour la bonne définition des orientations fonctionnelles d’ailleurs. La raison est avant tout économique.
Le coût d’une anomalie est très différent suivant la phase lors de laquelle l’anomalie est introduite et la phase lors de laquelle celle-ci est détectée. Ainsi, si une erreur de conception, détectée dès la phase de spécifications coûte 1 à corriger, la même erreur révélée lors des tests de qualification coûtera 10, et potentiellement jusqu’à 100 si le logiciel est déjà déployé. Le tableau suivant estime les rapports pour différents types d’anomalies en fonction de ces phases.
C’est pourquoi nous cherchons à valider un maximum de points en amont, avant qu’un effort important de développement, qui est par nature coûteux, ait été consommé. De plus, les anomalies sont plus faciles à comprendre et corriger sur un périmètre limité qu’au sein d’une application complète obligatoirement porteuse d’une certaine complexité.
L’évolution vers les méthodes agiles
Le positionnement des tests dans le temps est donc assez différent suivant que l’on utilise une méthode classique avec un cycle en V ou une méthode agile :
D’un point de vue humain, les méthodes agiles imposent une collaboration permanente, et cette collaboration entre les experts fonctionnels et les développeurs est le secret d’un logiciel réussi. Dans les méthodes plus traditionnelles, un formalisme poussé est souvent un moyen de se rassurer sur le plan théorique, mais c’est aussi un moyen pour les développeurs de s’abriter derrière des écrits pour ne plus effectuer de modifications, même si celles-ci répondent à un réel besoin. Le phénomène se produit également parfois avec les testeurs, alors que le testeur est l’ami du développeur, puisqu’il lui révèle ses erreurs !
En guise de conclusion, retenons que le test est un métier noble, qui comprend de multiples facettes, mais reste insuffisamment reconnu et valorisé, alors qu’il joue un rôle fondamental dans la qualité logicielle. Chacun pouvant par ailleurs évaluer son expérience quotidienne avec l’informatique, on conviendra aisément que des progrès restent à faire dans le domaine ! Alors que tous les développeurs et informaticiens se mobilisent pour redonner au test la place qu’il mérite.
10 conseils à retenir
- Le test est un vrai métier, il faut de réels rôles de testeurs distincts des développeurs.
- Le test ne doit pas être sous-évalué, de l’ordre de 25 à 30% de l’effort d’un projet de développement.
- Les jeux de tests doivent être réalisés tôt dans le cycle pour lever les erreurs de conception et faciliter le travail des équipes de développement.
- Une application doit toujours être conçue de manière à être testable, et un bon découpage en composants est une aide précieuse sur ce point.
- Il convient d’investir sur toutes les dimensions du test y compris l’acceptation par les utilisateurs et l’ergonomie.
- Il faut définir les conditions d’exploitation du système et tester les configurations, la montée en charge ou le comportement en cas de coupure réseau.
- C’est toujours une bonne idée d’investir sur l’automatisation pour l’ensemble des tests et en particulier pour valider la non-régression.
- Les tests sont des développements qui font partie du cycle de gestion des versions.
- Comme pour le développement, un travail partiel bien ciblé permet de couvrir l’essentiel selon une règle de 80/20. Il vaut mieux commencer par cela et améliorer par itération, que chercher à tout prix une exhaustivité utopique.
- Une approche statique fortement typée et pilotée par les modèles facilite les tests, à l’inverse d’une approche dynamique basée sur des métadonnées, qui est très souple pour le développeur, aboutit à une découverte tardive des difficultés.