Tout a commencé il y a maintenant quelques mois, lorsque l'un des membres actuels de l'équipe de développement d'Atoum m'a contacté pour me poser une question sur la façon d'écrire des tests unitaires.

À l'époque, il ne participait pas encore au développement du projet, et s'il connaissait parfaitement l'aspect théorique des tests unitaires et qu'il prônait leur utilisation, c'était la première fois qu'il devait effectivement les mettre en pratique.

Et comme la plupart des débutants dans les tests unitaires, il s'est demandé comment il était possible de tester une méthode de classe privée ou protégée.

J'avoue avoir répondu sans réfléchir, tellement la réponse me semblait évidente.

À mon sens, il n'est pas nécessaire de tester ces méthodes.

Et pourquoi donc me direz-vous ?

Tout d'abord, pour en finir immédiatement avec mon argument le plus subjectif, je pense que les solutions permettant de tester ces méthodes ne sont pas propres ou bien relativement lourdes à mettre en œuvre.

Ensuite, l'encapsulation, qui se traduit en PHP par l'utilisation des mots clefs protected et private affectés à une propriété ou une méthode de classe, a pour but de masquer l'implémentation technique de la classe à son utilisateur.

Or, de mon point de vue, un test unitaire valide l'implémentation de la classe du point de vue de son utilisateur, et non du point de vue de son développeur.

C'est pour moi avant tout un contrat passé entre le développeur et l'utilisateur, qui garanti à ce dernier que l'interface publique de la classe se comportera comme elle le doit, ni plus ni moins.

Il est donc logique que je ne me soucis pas de tester les méthodes protégées ou privées de mes classes, puisque seul compte à mes yeux le fait que les méthodes publiques de ma classe se comportent correctement.

De plus, lorsque l'on fait du développement piloté par les tests, ce qui est mon cas, le processus à suivre pour créer une classe est le suivant :

  1. le développeur écrit un test pour une méthode publique de la classe.
  2. Le développeur écrit le code le plus simple possible qui permet à la classe de réussir le test écrit précédemment.
  3. Le développement se poursuit de cette manière tant que le comportement des fonctionnalités devant être assurées par la classe n'est pas intégralement défini par les tests.

Et le mot le plus important dans ce qui précède, outre le mot publique, est simple.

Par simple, j’entends même naïf, dans le sens ou il est par exemple permis de faire de la duplication de code, d'utiliser des algorithmes peu efficaces, et surtout de ne pas se soucier de l'encapsulation.

L'encapsulation n’apparaît que lors de l'étape de refactorisation, qui intervient à l'issue du processus décrit ci-dessous, et qui a pour but de passer d'une implémentation naïve à une implémentation faite dans les règles de l'art, avec la garantie que la classe continuera à se comporter comme elle le doit grâce aux tests écrits précédemment.

Comme vous pouvez le constater, il n'y a pas de place pour des tests relatifs aux méthodes protégées ou privées dans ce processus, puisqu'elles sont une conséquence de la refactorisation et n'apparaissent aucunement lors de l'écriture des tests.

Enfin, J'ai un autre argument pour justifier le fait qu'il est inutile de tester les méthodes protégées ou privées d'une classe.

L'encapsulation ayant pour but de masquer l'implémentation d'une classe, elle permet de faire de la refactorisation à tout moment au cours de la vie de la classe sans impacter l'utilisateur de la classe.

Il est donc tout à fait possible de modifier de manière très radicale le fonctionnement interne de la classe sans que l'utilisateur final en ait conscience.

Or, si les méthodes privées et protégées sont testées, il faut que le développeur, lorsqu'il effectue la refactorisation, modifie également les tests, ce qui représente un travail supplémentaire non négligeable.

De plus, lors de ce processus, les tests ne sont pas censés être modifiés puisqu'ils sont là pour garantir que le comportement de la classe ne change pas malgré les modifications effectuées sur l'implémentation.

Évidement, le camp adverse a également des arguments lui permettant de justifier la définition de tests pour les méthodes privées et protégées, et celui qui revient le plus souvent est qu'il est difficile de localiser précisément un bug ou une régression si ces méthodes ne sont pas testées.

Je répond à cela qu'un test unitaire n'est pas un débugger et qu'il ne remplace pas un cerveau, mais vous vous doutez bien qu'il est assez mal reçu.

L'autre argument récurrent est que, selon eux, je pense que l'unité dans mes tests est la classe, alors qu'ils considèrent que l'unité est la méthode.

J'avoue que ce n'est pas entièrement faux, même si je me plaît à préciser que pour moi, l'unité est la méthode publique et non la classe.

Évidemment, ce débat est une bataille de chapelles, et en tant que tel, il n'aura jamais de réponse absolu, d'autant que le monde des tests unitaires évolue.

Il y a en effet des gens comme Ivan Enderlin, le créateur du framework PHP Hoa, dont c'est le métier de réfléchir à ces problématiques.

Et à force de réfléchir, il a trouvé un moyen novateur de réaliser des tests, qui n'est pas une autre façon de faire des tests unitaires, mais plutôt une technique complémentaire qui permet entre autre de ne pas se préoccuper de l'encapsulation.

Je ne vous donnerais aucun détail sur ce qu'il propose, car je considère que c'est à lui de le présenter, et de plus, je pense que cela mériterait bien plus qu'un simple billet.

J'ajouterais de plus que je ne suis pas entièrement convaincu par ce qu'il propose, et je suis donc assez mal placé pour parler de son travail.

Je considère cependant qu'il a trouvé une nouvelle voie qu'il est intéressant de suivre un minimum, ne serait-ce que pour voir ou elle peut mener.

Vous l'aurez compris, le débat sur l'intérêt de tester les méthodes privées et protégées n'est pas prêt de se terminer, la preuve en étant que ce débat a, depuis la question d'origine, débordé du cadre d'Atoum, puisque j'ai eu l'occasion de discuter de ce sujet sur twitter ainsi qu'au forum PHP 2010 avec des gens totalement externes au projet.

Et pour ceux qui se poseraient éventuellement la question, Atoum est potentiellement capable de gérer les deux philosophies, et je n'ai aucun problème pour travailler avec quelqu'un qui défend un point de vue opposé au mien de manière constructive, bien au contraire.

Je considère en effet que c'est de la différence, du débat, qu'émerge les idées novatrices, car cela nous force à voir les choses sous un autre angle.

Je suis donc extrêmement heureux d'avoir une force contradictoire au sein de l'équipe de développement !