Test Unitaires: Comment empêcher les bugs
Il y a un dicton parmi les développeurs : L'erreur est humaine... mais pour vraiment tout foutre en l’air, rien de tel qu’un ordinateur. Ce dicton met en exergue notre problème, en tant que développeurs: Notre code est fragile. Il se casse. Comment résoudre ce problème ?
Bonjour, je m'appelle David, et dans cette vidéo, nous allons explorer ensemble comment faire en sorte que notre code ne... mette pas tout en pagaille. Et nous verrons que la solution à ce problème présente plusieurs avantages supplémentaires. Dont un auquel vous n'aviez probablement pas pensé.
Mais d'abord, pourquoi avons-nous ce problème ? Pourquoi notre code est-il fragile ?
Tout d'abord, c’est impossible de garder en tête toutes les informations dont nous avons besoin. Les besoins, les exigences et la technologie... évoluent. Les systèmes auxquels nous avons affaire ont des interactions complexes. Il est impossible pour votre cerveau de retenir toutes les règles et tous les comportements qui sont censés se produire. Toutes les spécifications. Tous les cas d'utilisation. Tout ce que le code est censé faire.
Comment pouvons-nous résoudre cela ?
Avant d'aborder ce sujet... la situation est (en fait) encore pire qu'il n'y paraît.
Parce qu'en tant que développeurs, certains des systèmes sur lesquels nous travaillons gèrent des ressources vitales. Nous pourrions être en train de nous assurer que les gens sont payés à temps, ou qu'ils reçoivent leurs cadeaux de Noël... ou de gérer des stocks qui signifient la vie ou la mort pour les patients dans les hôpitaux, ou de coder des voitures auto-conductrices.
Évidemment, (et heureusement,) tout ce que nous faisons n'a pas autant d'importance. Mais _quelques-uns le font. Et même si tout ce que nous faisons est de rendre la vie de quelqu'un plus facile, avec un outil, ou plus amusante, avec un jeu... Eh bien, c'est important aussi. Les gens dépendent de notre code.
Comment pouvons-nous nous assurer que notre code ne gâche pas tout au mauvais moment ?
Soyons francs : ce n'est pas humainement possible. Il y a trop d'informations à retenir dans nos cerveaux. C'est trop complexe, c'est au-delà de nos capacités. Mais heureusement, j'ai de bonnes nouvelles.
Tout cela est à la portée d'un ordinateur !
Voici ce que nous pouvons faire : écrire du code supplémentaire et demander à ce code de tester le nôtre. Et ça, mesdames et messieurs, c'est l'essence même des tests automatisés. Il s'agit d'écrire plus de code, pour tester automatiquement que votre code fait ce qu'il doit faire.
Et quels sont les différents types de test ? Et quels sont les avantages supplémentaires ? Mais d'abord : comment cela fonctionne-t-il en pratique ?
Eh bien, en gros, nous prenons notre code - une fonction, par exemple - et nous disons : lorsque j'envoie cette entrée à la fonction, elle devrait retourner ceci. L'exemple canonique de base est le suivant : si j'appelle la fonction add
avec 2 et 3, elle devrait retourner 5. Ce concept de base peut être étendu jusqu'aux interactions avec l'interface. Par exemple, sur un site Web : si je clique sur le bouton du site, et que je saisis un login et un mot de passe qui sont valides, vérifiez que je suis redirigé vers la page suivante.
Le test simple et atomique de fonctions qui n'ont qu'une logique interne, qui ne dépendent pas de l'état d'autres parties du code (ou pour utiliser le terme technique, des fonctions "pures"), est appelé test unitaire.
Tester l'ensemble du système comme dans mon exemple avec l'écran de connexion est appelé test "de bout en bout" ou "UI". Et il existe un niveau intermédiaire qui est le test d'"intégration", où nous n'interagissons pas avec l'interface utilisateur complète, mais où nous nous assurons tout de même que les bits fonctionnent ensemble.
Il s'agit généralement d'appeler une API ou une fonction complexe qui utilise d'autres parties du code.
Et ma façon préférée de tester est en fait cette façon intermédiaire : les tests d'intégration. Pourquoi ?
Tout d'abord, les tests de bout en bout ont tendance à dépendre de la façon dont l'interface utilisateur est implémentée. Et s'il y a une chose qui est restée la même au cours des très nombreuses années où j'ai développé, tant dans les jeux que dans les applications et les sites Web, c'est que les interfaces utilisateur changent beaucoup. Donc les tests de bout en bout sont une plaie.
À l'inverse, les tests unitaires signifient qu'il y a beaucoup de code à écrire, pour chaque petite fonction.
Les tests d'intégration sont le juste milieu. Ils nous permettent de tester une plus grande partie du code de base en un seul appel.
(Oh, et accessoirement, la proportion du codebase qui est couverte par les tests automatisés est appelée "couverture", vous pouvez voir des badges montrant la couverture sur les dépôts GitHub).
Maintenant :
Les quatre avantages de tester automatiquement votre code ?
Une stabilité accrue
L'avantage le plus évident de la mise en place de tests automatiques de votre code est qu'il offre une meilleure stabilité. Votre code est moins susceptible de se casser. Ou plutôt, s'il se casse, vous le saurez tout de suite. Si vous avez mis en place l'intégration et le déploiement continus, ou CI/CD, vous pouvez ajouter les tests au déploiement pour vous assurer que vous n'envoyez que du code propre.
Mais la stabilité n'est pas le seul avantage.
Refactoring plus facile
Vous voyez, nous avons souvent besoin de remanier notre code. Pour écrire le code d'une manière plus propre. Ou d'une manière qui prend en compte les nouvelles informations ou technologies. Lorsque nous faisons cela, nous voulons nous assurer que le code a le même comportement avant et après avoir été remanié.
Et il n'y a pas de meilleur moyen de le faire que de mettre en place des tests automatisés. C'est une sorte de contrat qui dit : voici ce que nous attendons comme résultat lorsque nous produisons cette entrée. Parce que lorsque nous refactorons, nous voulons essentiellement un code mieux écrit qui fait la même chose qu'avant. Et s'assurer que le comportement du code ne change pas est précisément ce pour quoi les tests automatisés sont les meilleurs.
Mais ce n'est pas le seul avantage.
Meilleure architecture et débogage
Vous voyez, lorsque nous mettons en place des tests, cela nous oblige à structurer notre code différemment.
Imaginez que vous voulez tester. Imaginez que vous avez une fonction qui fait des tas de choses, comme appeler une API, puis faire des tas de choses avec les données et les sauvegarder, et que cela ne fonctionne pas. Je dis "imagine" mais c'est précisément ce qui m'est arrivé la semaine dernière. J'adaptais un extrait de code que j'avais obtenu d'un article du blog d'AWS. Et une partie de celui-ci ne fonctionnait pas.
Et écrire des tests m'a permis de comprendre rapidement d'où venait le bug. Mais écrire les tests, et structurer mon code de façon à ce qu'il puisse être testé, m'a permis d'écrire un meilleur code parce que j'ai fini par mieux isoler les différents morceaux de la longue fonction en petits morceaux plus faciles à gérer.
Maintenant, avant d'aborder le quatrième avantage, nous devons parler d'autre chose :
Abonnez-vous pour mieux comprendre le développement logiciel. Recevez les dernière nouvelles, vidéos et conseils.
Quels sont les coûts, les inconvénients et les pièges des tests automatisés ?
Les inconvénients des tests automatisés. Parce que tout n'est pas parfait.
Par exemple, vous pouvez aussi tomber dans le piège d'écrire trop de tests pour des choses qui ne le méritent pas. Je veux dire, dans les tests de la vie réelle, la fonction add est tout simplement stupide : nous savons que l'opérateur plus fonctionne, et s'il ne fonctionne pas... alors nous avons d'autres problèmes.
À l'inverse, si vos tests ne couvrent pas les cas d'erreur, ils peuvent vous donner un faux sentiment de sécurité. Vous pouvez finir par penser que les choses fonctionnent parce qu'un test passe, mais si vous ne testez pas vraiment tous les cas, votre code pourrait ne fonctionner que partiellement.
Enfin, on a parfois l'impression que l'écriture des tests est tout aussi longue et compliquée que l'écriture du code lui-même.
Mais même ce coût supplémentaire en vaut la peine lorsque vous voyez le quatrième et dernier avantage.
La tranquillité d'esprit
Vous voyez, parfois les gens dépendent du bon fonctionnement de votre code. Et cela peut être stressant. Les tests automatisés vous donnent la tranquillité d'esprit que votre code se comporte comme il le devrait. Que les messages sont envoyés. Que les paiements sont livrés. Et cette sécurité, cette tranquillité d'esprit, peut être vitale pour notre santé mentale, en tant que développeurs. Elle supprime le stress.
Et ceci même si parfois on peut avoir l'impression que les tests automatisés rajoutent du temps de développement.
Mais les tests sont en fait un gain de temps à long terme. Parce que des tests bien écrits peuvent fonctionner comme une documentation et une sauvegarde. Ils sont un investissement contre la dette technique. Ils permettent de découvrir et de résoudre les bogues beaucoup plus rapidement.
Les tests automatisés sont un outil indispensable à avoir dans votre boîte à outils. Tant pour la qualité de votre code que pour votre tranquillité d'esprit.