Passer au contenu principal

Dans un précédent article nous vous avons parlé de la démarche devops. Les tests automatisés sont une composante essentielle de cette démarche, et nous allons voir pourquoi.

On pourrait penser que les testeurs suffisent pour valider le bon fonctionnement d’une application, mais cette assertion ne résiste pas à une analyse un peu approfondie. Tout d’abord les applications deviennent énormes, aussi il n’est pas possible humainement de tester dans des temps raisonnables une application comprenant plus de dix mille cas de tests. Aussi ce fonctionnement implique les désagréments suivants :

  • Il existe un temps important – souvent plusieurs semaines – entre le moment où le code est écrit et le moment où il passe entre les mains des testeurs. Aussi pendant ce temps les développeurs ont le temps d’oublier pourquoi ils ont implémenté la fonctionnalité de telle ou telle façon d’autant que le code n’est que rarement documenté. Ceci accroît donc les aller-retours entre les développeurs et les testeurs, avec des risques de régression car rien ne garantit que la correction d’un bug ne va pas casser quelque chose ailleurs qui ne sera pas retesté car « le test passait avant ».
  • Bien souvent les plannings sont assez serrés, ce qui fait que les campagnes de test complètes sont rarement menées à leur terme.
  • Ce système empêche les livraisons de micro-releases, qui ne contiennent qu’une ou deux évolutions. Or c’est ce système qui permet d’avoir le plus fréquemment un retour des utilisateurs, et corriger rapidement les applications si besoin.
  • Certains tests de prérequis non fonctionnels, comme la performance ou la sécurité, ne sont pas menés faute de temps. Ceci accroît le stress lors de la mise en production du fait que la confiance dans l’application reste faible.

Il existe pourtant un moyen relativement simple de se sortir de cette situation : en automatisant tous les tests qui peuvent être automatisés, autrement dit pratiquement tout sauf le rendu visuel. Alors bien sûr cela implique une plus grande discipline de tous les intervenants, mais c’est pour le bien de tous !

Pour les développeurs

La première chose que doivent écrire les développeurs : les tests unitaires. Une bonne pratique pour les mettre en place est d’utiliser le Test Driven Development (TDD), ce qui permet d’écrire du code testable facilement. En effet un développeur se doit d’être fainéant, or du code non testable oblige à ne pas être flemmard donc ce n’est pas bon. Eh oui la paresse est une grande qualité en informatique, car cela oblige à être créatif !

Ensuite ces tests unitaires doivent être exécutés à chaque commit par un serveur d’intégration continue, afin de permettre de savoir si un commit casse tel ou tel test. Cela implique les choses suivantes :

  • La suite de tests unitaires doit s’exécuter rapidement, typiquement moins de dix minutes pour une application complète. Sinon les tests ne seront pas exécutés par les développeurs.
  • Lorsque le serveur d’intégration continue indique un échec d’un ou plusieurs tests, les développeurs responsables des derniers commits doivent interrompre leur travail en cours pour corriger les tests qui échouent. Ceci requiert une certaine discipline.

Par la suite la règle est très simple : si un test unitaire échoue l’application ne peut être fournie aux testeurs. Et pas la peine de commenter un test pour tout faire passer… 😉

Dernier point et non des moindres : une application est considérée comme correctement couverte par les tests unitaires si au moins 80% du code est couvert. Et il est indispensable de mettre des assertions dans les tests car sinon ceux-ci sont inutiles !

Les tests d’intégration

Les tests d’intégration permettent de vérifier que les appels au serveur fonctionnent correctement. Ils n’ont pas besoin d’être exécutés aussi fréquemment que les tests unitaires, une fois par jour suffit. Les tests d’intégration ne vont pas vérifier le comportement de l’interface homme machine (IHM), aussi il peut être de bon aloi de ne pas coupler celle-ci avec l’application en elle-même. Nous fournissons quelques informations dans cet article pour y arriver. Par ailleurs le fait que la communication entre l’IHM et l’application se fasse par l’intermédiaire d’une interface de type REST peut être aussi d’une grande aide.

Un bon moyen de mettre en oeuvre ces tests pour une application est la méthode suivante :

  • Tout d’abord recharger une base de données connue, afin de repartir d’un état maîtrisé. Cette base n’a pas besoin d’être une copie de celle de production, cela mettrait trop de temps à charger. Il suffit qu’elle soit un sous-ensemble de cette base comprenant les cas d’utilisation intéressants.
  • Dérouler la suite de tests. Typiquement on passera par un client http qui exécute une batterie de tests. Ceci dit à ce niveau il vaut mieux les exécuter séquentiellement pour éviter d’induire des faux positifs dans les résultats dûs au multithread.
  • Enfin récupérer les résultats, et si un test d’intégration est cassé, le corriger.

Tout comme pour les tests unitaires si un test d’intégration échoue la version ne doit pas partir chez les testeurs.

Dernier point : pour être sûr d’exécuter les test d’intégration correctement, il convient de déployer automatiquement l’application dès lors que les tests unitaires passent. Ce déploiement doit se passer une fois par jour, juste avant l’exécution des tests d’intégration.

Pour les testeurs

On pense souvent que le travail des testeurs ne concerne que les tests fonctionnels, cependant ceux-ci ne sont qu’une partie du travail. Les tests non fonctionnels, tels que les contraintes de performance, sont tout aussi importants. Aussi il est important que la plateforme sur laquelle les tests sont exécutés soit en tout point identique à la production, sur le plan logiciel, et pour les tests de performance ceci doit aussi être le cas en terme de matériel.

Les tests fonctionnels

Les tests fonctionnels sont habituellement définis de la manière suivante :

  1. Etant donné la situation X
  2. Si je fais l’action Y
  3. Je dois obtenir la situation Z

Il est important de noter que ces tests fonctionnels doivent être définis en collaboration avec les développeurs afin que ceux-ci puissent aussi s’adapter aux pré-requis de l’application. Idéalement la spécification fonctionnelle de l’application devrait être essentiellement définie par les tests !

Et là on se rend compte que pour tout ce qui n’est pas de l’IHM on peut automatiser le travail, pour peu que l’application ait été architecturée comme défini précédemment. Dès lors il existe deux possibilités :

  • Soit les testeurs codent eux-mêmes les tests, mais les problèmes de communication entre équipes peuvent occasionner de faux positifs.
  • Soit les testeurs travaillent en collaboration avec les développeurs en pair programming, avec le testeur qui donne la spécification du test et le développeur qui l’implémente. Cette dernière méthode permet notamment aux développeurs de coder un client pour l’application qui simplifie l’écriture des tests et leur maintenabilité, et implique davantage les testeurs également. Aussi elle doit être préférée.

Si un test fonctionnel ne passe pas pour une release donné, l’application peut cette fois éventuellement passer à l’étape suivante car certains cas de tests évoqués ici peuvent ne pas être critiques pour l’application, ou ne plus être valides et donc supprimés dans ce dernier cas. Cette décision doit être prise par les testeurs en collaboration avec le management et les développeurs.

A ce niveau, les seuls tests qui restent à faire manuellement sont ceux de rendu, mais comme tout le côté fonctionnel a déjà été testé le travail restant à faire est nettement moindre !

Les tests fonctionnels automatisés doivent être exécutés régulièrement, par exemple une ou plusieurs fois par semaine, afin de fournir un retour rapide aux développeurs sur leur travail. Ceci implique néanmoins un déploiement automatisé de l’application, dès lors que les tests d’intégration sont passants. Pour les tests visuels ceci doit être fait à la demande.

Les tests non fonctionnels

Comme indiqué les tests non fonctionnels incluent notamment :

  • Les tests de performance
  • Les tests de sécurité

A noter que contrairement à ce qu’on pourrait penser ces tests sont au moins aussi importants que les tests fonctionnels. En effet personne n’a envie de se retrouver avec une application qui met deux heures à répondre, ou qui expose ses données aux quatre vents !

Les tests de performance

Nous avons indiqué dans cet article comment réaliser des tests de performance. Le tout est ensuite d’automatiser la lecture des résultats et de considérer les tests en échec si un certain seuil est franchi.

Les tests de sécurité

Les tests de sécurité sont nettement plus complexes à définir. On pourra notamment s’inspirer de cette série d’articles, néanmoins pour les définir il peut être bon de faire appel à une équipe spécialisée dans le domaine, suivant le niveau de sécurité attendu. Cependant des tests d’authentification et d’Access Control Lists peuvent être relativement simples à mettre en place et codés sur le modèle des tests fonctionnels.

Le mot de la fin

Une petite citation pour finir, qu’on trouve un peu partout sur Internet mais dont je n’ai pu trouver l’auteur : Untested code is broken code. Elle résume tout à elle seule. 😉

Cet article vous a plu ? Vous aimerez sûrement aussi :

Julien
Moi c’est Julien, ingénieur en informatique avec quelques années d’expérience. Je suis tombé dans la marmite étant petit, mon père avait acheté un Apple – avant même ma naissance (oui ça date !). Et maintenant je me passionne essentiellement pour tout ce qui est du monde Java et du système, les OS open source en particulier.

Au quotidien, je suis devops, bref je fais du dév, je discute avec les opérationnels, et je fais du conseil auprès des clients.

Son Twitter Son LinkedIn

Rejoignez la discussion 2 Commentaires

  • Karim dit :

    Hello Julien,

    Merci pour cet article intéressant ! Je trouve toutefois dommage que tu ne pousses pas plus loin, notamment avec le BDD et les outils type Selenium pour justement automatiser les tests de l’IHM.
    As-tu déjà utilisé ce type d’outil ? Quel est ton retour d’expérience sur le sujet ?

  • gojul dit :

    Bonjour,

    Pour les tests d’IHM il vaut mieux utiliser des outils du type QTP que Selenium. En effet les IHM changent souvent, or une partie du rôle des tests est de valider la non-reg. Le souci est que Selenium est très sensible aux changements dans le DOM et il faut vite modifier les tests, ce qui à terme les rend très chers à maintenir à moins d’organiser le HTML avec des identifiants. D’autre part Selenium ne permettra jamais de garantir un rendu visuel, car rien ne garantit avec cet outil que ton application sera « jolie » et qu’il n’y aura pas des arrangements faits n’importe comment.

    Par ailleurs je n’étais pas dans une logique d’outils mais dans une logique de présentation d’une démarche. Il s’agit là de deux choses différentes, même si pour certaines choses il y a des standards de fait tels que xUnit. Mais la démarche DevOps dont fait partie cet article ne concerne pas les outils mais une méthodologie.

    Effectivement je n’ai pas parlé directement du BDD même si dans l’article je l’évoque en filigrane dans les tests fonctionnels. Mais bon déjà quand les démarches devops seront généralisées on pourra s’intéresser davantage à ce topic. 🙂

Laisser un commentaire