Chez ELEPHANT, nous mettons tout en place pour aider nos elephantgénieurs hardware, embarqué, software et web à atteindre leur objectif. ✔️
Notre ESN a pour but de faire grandir ses collaborateurs humainement et techniquement en les accompagnant dans chaque étape de leur projet. 🐘

Dans cet article nous allons évoquer le sujet des tests et leur importance capitale qu'ils occupent au sein d'un projet informatique.
 

Pour commencer voici une définition de l'Insee d'un test : « Le test consiste à exécuter et évaluer un système ou un composant sous des conditions spécifiques, pour vérifier qu’il répond à ses spécifications ou pour identifier des différences entre les résultats spécifies et attendus et les résultats effectivement obtenus » (IEEE, 1990)



 

➡️ Les tests et leurs bonnes pratiques au sein d’une application 



 

Pour résumer le but d'un test, pour un projet informatique, et de tester une fonctionnalité de l'application afin d’en comparer un résultat obtenu et un résultat attendu. Il permet aussi de déceler des anomalies afin d'en améliorer la qualité. ✔️

 

Au sein d'un projet informatique on va relever 3 types de tests majeurs :
 

 

  • Tests unitaires
     
  • Tests fonctionnels
     
  • Tests automatisés


     

1️⃣ Les tests unitaires
 

 

Le fonctionnement d'un test unitaire est simple, au sein de l'application une classe est créée. Dans cette classe nous allons faire appel à différentes fonctions tout en simulant les données en entrée, le résultat obtenu est alors comparé au résultat attendu. La classe est composée d'une multitude de fonctions dont chacune d'entre elles va tester une ou plusieurs fonctionnalités et va effectuer la comparaison. 

 

Les tests unitaires sont à la charge du développeur. En effet, lorsqu'une nouvelle fonctionnalité est mise en place par un développeur, il est de sa responsabilité, contractuelle ou non, de la tester. 👨‍💻

 

Dans le cadre des tests unitaires on entend beaucoup parler du Framework Mockito mais aussi du JUnit. Ces outils ont pour but de faciliter la mise en place des cas tests au niveau des jeux de données mais aussi la comparaison des résultats.

 


Afin d’être plus explicite prenons en exemple une voiture qui va nous être utile comme analogie des tests unitaires, fonctionnels mais aussi automatisés. 🚗⚙️

 



Partons du principe que notre voiture est l'égal d'une application web, la carrosserie, les compteurs, tout ce qui voit de l’extérieur étant le front, ce que l'utilisateur voit au travers de son navigateur web et le moteur, les câbles etc… étant ce qu’on appelle back c’est-à-dire l’application contenant le code. 

 

Dans cette analogie les tests unitaires seraient une sorte de petit boîtier branché directement au moteur ou à certains câbles. Ce boîtier enverrait des impulsions permettant de simuler l'utilisation de la voiture. On peut prendre comme exemple le fait d'accélérer, via ce petit boîtier on va simuler l'appui de la pédale directement au moteur et on va pouvoir constater ou non si le moteur monte dans les tours du fait de l'accélération.
Les tests unitaires ont une place capitale au sein d’une application informatique. Il permet de tester les différents cas nominaux de l'application, de constituer une banque de tests de non-régression.

Ainsi lorsqu'une nouvelle fonctionnalité est déployée l'ensemble des tests unitaires précédents vont être joués afin de déterminer si le nouveau code n'impacte pas le fonctionnement des anciennes fonctionnalités


 

Aujourd’hui dans la plupart des projets les tests unitaires sont faits a posteriori du développement. De nombreuses études ont démontré que cette pratique n'est pas optimale. En effet, de façon consciente ou non, la personne aura tendance à orienter ces tests unitaires afin qu'ils ne posent pas de problème. Il pourrait passer à côté de bug ou d’un cas aux limites qu'il ne serait pas traité par le développement.

Une méthodologie permet de pallier ces problèmes au nom de TDD (Test-Driven Development) et a pour principe de commencer par les tests unitaires et d’ensuite effectuer le développement de la fonctionnalité. 

 

De ce fait on pose à plat directement les valeurs en entrée et le résultat attendu en partant du principe que la fonctionnalité n'est qu'une simple boîte noire dont le traitement nous permettra d'obtenir le résultat voulu. On peut dès lors poser tous les cas nominaux et les cas aux limites possibles et le développement de la fonctionnalité devra répondre à tous ces critères.

 

Il sera toujours important de bien commenter les méthodes de tests afin d’aider les développeurs qui auront à les modifier dans le futur à les comprendre. On essayera donc toujours d’expliquer quelle partie du code est testée, sous quelles conditions, et quels sont les résultats attendus. 


 

La structure des tests unitaires s’axe autour de trois blocs principaux, souvent délimités par des commentaires pour faciliter la lecture du test :

 

  • Prepare 
     
  • Execute
     
  • Assert


 

1️⃣ Dans la première partie du test, le « prepare », on va créer les données passées en entrée à notre test, et toutes les données renvoyées par des méthodes mockées.


2️⃣ Dans la seconde, on appelle la méthode testée, et on récupère son résultat.


3️⃣ Enfin dans la dernière, on effectue notre batterie de tests, sans oublier, si certains peuvent paraître obscurs, de les expliquer en commentaires.


 

On va en général organiser les tests afin de retrouver dans un même fichier les tests provenant de méthodes elles-mêmes dans un même fichier, mais attention, en faisant ça on se retrouve avec plusieurs tests dans le même fichier de tests, et ces derniers seront lancés à la suite. Voilà pourquoi il faudra faire attention à ce qu’entre deux tests, on retourne toujours dans les conditions initiales, et qu’aucun test ne modifie le comportement d’un autre en changeant par exemple une variable globale.
 

Dans le cas de tests de méthodes se basant sur une base de données pour la lire / modifier, il ne faudra JAMAIS utiliser la base utilisée normalement par l’application, pour éviter que les données en base ne changent et que le test soit en échec suite à des manipulations de données.
On va donc créer des mini bases de données pour ces tests, par exemple des .xml, remplies à la main avec juste les données dont on a besoin pour vérifier nos tests. Encore une fois, on retourne toujours dans les conditions initiales avant chaque test pour s’assurer qu’aucun test ne modifie le comportement d’un autre en modifiant la base de données avant son exécution.

 

Il faut garder en mémoire que les tests unitaires sont importants mais il ne faut pas tester pour tester, avoir une couverture de 100% est impossible et faire des tests de getter / setter est très souvent inutile. En revanche, on n’exécute la méthode qu'une fois par test, donc si le test écrit ne suffit pas à couvrir entièrement la méthode, il ne faut pas hésiter à faire plusieurs tests pour couvrir cette dernière, en faisant attention d’utiliser des noms clairs et explicites. 💡

 

2️⃣ Les tests fonctionnels
 

 

Les tests fonctionnels interviennent une fois que le développement de la fonctionnalité et ces tests unitaires sont établis. Cependant contrairement aux tests unitaires ces tests sont faits directement via l'application. On retrouve différentes étapes dans le test et aussi un résultat attendu. 

 

Pour reprendre l’analogie de la voiture et le cas de l'accélération, le test fonctionnel va être d'utiliser la voiture et d'appuyer sur la pédale d'accélération et de constater ou non si le compte-tours augmente.

Ici les différents cas de tests pourront être de soi accélérer franchement, d'accélérer modérément ou de ne pas accélérer du tout. Le résultat devrait pouvoir être constaté sur le compte-tour. 🚗

 

Les tests fonctionnels sont séparés en deux étapes principales :

 

  • La première étant ce qu'on appelle la préparation qualification, il est de mettre en place les différents cas de tests et les différents résultats attendus avant même que la fonctionnalité soit développée.

     
  • Une fois la fonctionnalité disponible on passe à l'étape de la qualification. Une personne référente fonctionnelle, va dérouler les différents cas des tests et vérifier que les résultats obtenus sont en adéquation avec les résultats attendus lors de la préparation de la qualification.

 

➡️ Idéalement les deux étapes sont réalisées par deux personnes différentes car tout comme les tests unitaires si une même personne réalise les deux étapes lors de la qualification cette dernière pourra être tentée de dévier de façon marginale au cas de test afin d'obtenir le résultat attendu. 

Lors de ces tests fonctionnels on peut déceler une erreur dans le développement de la nouvelle fonctionnalité mais on pourra aussi constater de nouveaux bugs ou nouvelles anomalies en dehors du périmètre de la fonctionnalité et ceux de manière fortuite.

 

3️⃣ Les tests automatisés

 

Pour terminer nous allons parler des tests automatisés, ces derniers se rapprochent des tests fonctionnels. Ils ont eux aussi un cas de test avec différentes étapes à respecter et aussi un résultat attendu à correspondre. Cependant à l'instar des tests fonctionnels où une personne physique établit les différentes actions pour respecter le test ici dans les tests automatisés c'est une application qui va simuler l’utilisation de l’application

 

Des outils comme Cucumber permettent de simuler des clics souris ou encore des touches clavier. Pour reprendre l’exemple de la voiture ce n'est plus une personne à la place du conducteur qui va appuyer sur la pédale d'accélération mais plutôt une sorte de robot qui va appuyer sur la pédale. Contrairement aux tests fonctionnels, le test automatisé va respecter le cas de test à la lettre. Au fil des différents tests automatisés misent en place, une banque de tests se constitue afin de s'assurer qu’au cours des futurs développements les anciennes fonctionnalités sont toujours opérationnelles.

 

Contrairement aux tests unitaires où la base de données doit être réinitialisée avant chaque test, il est souvent intéressant pour les tests automatisés de conserver les données créées lors des tests précédents. Souvent car elles sont utilisées par la suite dans d’autres tests, ou qu’elles permettent d’accéder à une autre fonctionnalité de l’application, qui serait bloqué autrement.💡
 

 

🐘 Conclusion 🐘


 

Pour finir  sur le cycle de vie des différents tests au sein d’un projet informatique les tests sont une composante essentielle si ce n'est prioritaire. Certes chronophage et compliqué à mettre en œuvre au fur et à mesure que l'application étend ses fonctionnalités, les tests permettent d'assurer une utilisation pérenne de l'application. 👍


Les tests apportent de nombreux avantages pour un projet informatique. En effet les différents bugs et anomalies rencontrées pourront être traités directement à la source du problème.
Ils permettent de réduire les coûts de correction car une anomalie traitée avant même la mise en production coûtera logiquement moins chère. Ce n'est pas pour rien que de façon contractuelle un pourcentage de couverture de code est attendu des entreprises. ✅

 

Sources : 
 

https://www.zdnet.fr/actualites/de-l-importance-des-tests-pour-reussir-un-projet-de-deploiement-2102491.htm

https://cucumber.io/
 

https://site.mockito.org/

https://openclassrooms.com/fr/courses/3504461-testez-linterface-de-votre-site/4270571-apprenez-le-test-driven-development-tdd