Tests unitaires #4: Il faut rendre ‘public’ les méthodes ‘private’ pour atteindre 100%

Dupdob
4 min readApr 1, 2022

--

Cet article fait partie d’une série dédiés aux tests unitaires et au TDD. L’introduction est ici.

Il faut que je vérifie tes parties privées
Il faut que je vérifie tes parties privées

Encore une fois, NON!

Les méthodes privées peuvent et doivent être testées à travers les points d’entrée publiques. Une fois de plus, tester ‘unitairement’ ce n’est pas tester isolément chaque méthode.

Se poser la question de comment tester les méthodes privées est un signe flagrant que vous comprenez pas ce qu’est le TDD. Si c’est le cas, je vous recommande de vous concentrer sur le BDD. Une fois que vous aurez compris le Behavior Driven Development vous pourrez alors revenir au TDD; en passant, le BDD a été inventé par Dan North en réaction à la mauvaise compréhension du TDD, en mettant en avant explicitement la notion de comportement.

Ok, j’ai compris mais j’ai du mal

Si certaines parties du code (privé) sont difficiles à tester, c’est peut être que ce code n’est pas indispensable.

J’en profite pour faire une petite parenthèse sur les outils: pour tirer tous les bénéfices des test unitaires, il faut ceci soit lancé fréquemment, idéalement en temps réèl, et il faut que vous puissiez voir les lignes de code non couvertes par des tests (ce qui est plus utile que le pourcentage). En C# il y a l’excellent NCrunch, on m’a dit beaucoup de bien de Wallaby en JS; pour Java je ne connais qu’Infinitest, mais je soupçonne qu’il y ait des alternatives; pour les autres langages, pas de référence désolé.

Les points blancs marquent les lignes non couvertes.
Les points blancs marquent les lignes non couvertes.

Un outil de couverture de test qui vous permet de voir quelles lignes ne sont pas couvertes par les tests est indispensable pour améliorer sa couverture, passé un premier stade. L’analyse de ces lignes vous permettra d’en vérifier l’intérêt et d’imaginer les tests unitaires qui les couvriront. Ce n’est plus vraiment du TDD puisque la démarche est en test after; et les radicaux du TDDs vous expliquerons que cela n’arrive pas puisque le code ne peut être écrit que pour faire passer un test, et que ce code doit être le code minimal pour le test.
Dans la vraie vie, nous sommes des humains et donc faillibles. Il arrive que du code non couvert apparaisse suite à un refactoring, il arrive aussi que nous ayons écrit un peu plus de code que nécessaire, par erreur ou par anticipation d’un besoin futur. Et il arrive que nous héritions de code non ou mal testé (unitairement).
Chercher à couvrir ce code sera une bonne occasion d’en confirmer l’intérêt: pas vraiment utile, on jette. Trop compliqué à ‘atteindre’ pour le couvrir ? N’est-ce pas du YAGNI?

Oui mais la gestion des cas d’erreur

Photo by Clint McKoy on Unsplash
Photo by Clint McKoy on Unsplash

Ah, voilà une bonne question!! Très souvent, le code non couvert correspond à des cas d’erreurs délicats à couvrir car quasi impossible à simuler. Est-ce vraiment utile de les tester ? Après tout, ces lignes de code ne sont pas censées servir ou alors très rarement.

Je vois 2 contre arguments:

  1. La gestion d’erreur est un sujet très complexe: cela demande d’élaborer des scénarios de panne et d’imaginer les moyens de les gérer ou d’y résister du mieux possible. C’est sans aucun doute du code parmi le plus complexe à mettre au point. ⇒ D’autant plus de raisons de le tester
  2. Les études montrent que la plupart des incidents sont aggravés (voir parfois déclenchés) par une gestion d’erreur inadaptée ou non testée.

Mes recommandations:

  1. Tester un maximum de scénario
  2. Isoler et réduire au maximum les bouts de code non testables et fournir des substituts (stubs/mocks) permettant de simuler les pannes
  3. Envisager une stratégie de type fail fast pour les cas non testable: plutôt que de tenter une technique de reprise/contournement en cas de panne, accepter le crash, mais garantir un redémarrage sain en contrepartie.

Conclusion

Si vous vous demandez comment tester les méthodes privées, c’est que vous avez pris de mauvaises habitudes et que vous avez été probablement mal formé au TDD/tests unitaires (confession: cela a été mon cas, et il m’a fallu quelques années pour sortir de l’ornière de 1 méthode de prod ⇒ 1 test).
Les parties privées doivent être testées à travers les cas d’usage, comme les autres.

  • Si tous les cas/situations ne sont pas testables, envisagez de simplifier le code.
  • Si certaines situations sont impossibles à reproduire dans un test, envisagez un mock. Voir simplifier à l’extrême (CF fail fast).
  • Enfin, n’hésitez pas à effacer du code non couvert et non testable: il est probable qu’ils ne servent à rien et/ou ne fonctionne pas.

--

--

Dupdob

Cyrille Dupuydauby. Convinced crafter , NewCrafts and Devoxx speaker, OSS maintainer, coding architect. Founder of the Speaker Academy