Tester les méthodes privées ?

Ionut Mihalcea
MoveNext
Published in
4 min readMar 4, 2024
Photo by Call Me Fred on Unsplash

TL;DR

C’est une question qui revient souvent, et aussi surprenant que cela puisse paraître, en 2024 il ne semble pas y avoir de consensus, ce qui suscite de nombreuses polémiques.

Si la question est : doit-on tester les méthodes privées ? Ma réponse est oui, mais pas directement. Ce que l’on veut tester c’est un comportement qu’une classe expose à travers ses méthodes publiques, alors que les méthodes privées ne sont que des détails d’implémentation. On ne veut pas tester les méthodes privées directement, mais on veut tester leur effet sur le comportement de la classe. Autrement dit, les tests des méthodes privées sont indirects, en les effectuant via les méthodes publiques qui les utilisent.

Que veut dire unité quand on parle de test unitaire ?

Avant d’aller plus en profondeur sur le sujet, je vais me pencher sur ce qui à mon avis est la raison pour laquelle cette question est encore posée.

Selon une définition commune que l’on peut trouver sur wikipedia : “en programmation informatique, le test unitaire (ou « T.U. ») est une procédure permettant de vérifier le bon fonctionnement d’une partie précise d’un logiciel ou d’une portion d’un programme « unité »”.

Cette définition est vague et la notion d’unité est floue. On peut considérer que l’unité est une méthode, une classe, un module, un composant, un système, etc…

J’ai rencontré des personnes qui considèrent que l’unité est la méthode ou la fonction, et qu’une bonne couverture de test implique que toutes les méthodes soient testées en isolation. À mon avis cette vision est trop réductionniste, et se trouve à la source de la question de savoir si on doit tester les méthodes privées. En effet quand on considère que l’unité est la méthode, il est naturel de se demander si on doit tester les méthodes privées. Et comme elles ne sont pas accessibles depuis l’extérieur de la classe, on se demande comment les tester.

Si l’on creuse un peu plus le sujet et la littérature on arrive à la conclusion que ce qui est important est de tester un comportement particulier et non pas la structure interne du code qui le produit. Dans le cadre du paradigme de la POO cela se fait en testant les méthodes publiques de la classe.

Les tests doivent être couplés au comportement du code et non pas à sa structure.

Que faire dans le cas où un comportement privé est suffisamment compliqué pour nécessiter des tests indépendants ?

C’est une situation qui peut arriver. Dans ce cas mon réflexe est de me demander si je ne devrais pas extraire cette partie du comportement dans une autre classe avec une interface et des responsabilités claires. Cela permet de rendre le code plus modulaire et plus facile à comprendre.

Cette nouvelle classe sera utilisée par la classe d’origine dont on peut désormais simplifier les cas de tests.

Objection fréquente : mais dans ce cas les tests ne sont plus “unitaires”

Vous l’aurez compris, au départ j’avais une seul classe A avec une méthode privée et suite au refactoring je me retrouve avec un classe supplémentaire B qui est utilisée par A. Souvent on apporte une objection du fait que A utilise B ce qui impliquerait que le test ne soit plus unitaire. Et c’est évidemment faux.

À ce stade, je vais revenir à la notion d’ “unité” et à une distinction que Martin Fowler fait en classant les tests en deux catégories : les tests solitaires et les tests sociables.

Dans le cadre des “sociable tests” les principes des “tests unitaires” sont préservés car les tests continuent à se focaliser sur le comportement d’une seul classe A ou B. Le fait que A utilise B est un détail d’implémentation.

Les “solitary tests” reposent massivement sur l’usage des doublures de tests (“stubs”, “spys”, “mocks”, “fakes”) et il est désormais connu que leur usage intensif et maladroit peut conduire à des tests fragiles. Mais cela ne veut pas dire qu’il n’existe pas des situations où ils sont pertinents.

Le choix entre tests “sociables” ou “solitaires” est piloté par la réponse à la question suivante : “que suis-je entrain de tester ? Le comportement souhaité ou mon implémentation ?”

Quelles sont les propriétés d’une bonne approche pour les tests unitaires ?

Finalement cela me semble être la question la plus importante, et pour y répondre je vais faire appel à Kent Beck. Selon lui nous pouvons savoir si nous avons une bonne approche si :

  • les tests retournent les mêmes résultats indépendamment de l’ordre dans lequel ils sont exécutés.
  • les tests retournent les mêmes résultats indépendamment du nombre d’exécutions.
  • les tests sont déterministes. Si rien ne change, alors leur résultat ne change pas.
  • les tests sont rapides à exécuter.
  • les tests sont rapides à écrire comparativement au code à tester.
  • les tests sont compréhensibles à la lecture.
  • les tests sont sensibles au changement du comportement de l’application.
  • les tests ne sont pas sensibles aux changements de la structure du code de l’application.
  • les tests sont automatisés.
  • les tests aident au diagnostic. Si un test échoue on peut identifier rapidement la cause.
  • les tests apportent de la confiance. Si tous les tests passent, alors le code est bon pour partir en production ou pré-production selon les cas.

Références utilisées pour cet article:

--

--