web-dev-qa-db-fra.com

Pourquoi les tests unitaires de méthodes privées sont-ils considérés comme une mauvaise pratique?

Le contexte:

Je travaille actuellement sur un petit projet en Python. Je structure généralement mes classes avec des méthodes publiques qui sont documentées mais traitent principalement des concepts de haut niveau (ce qu'un utilisateur de la classe doit savoir et utiliser), et un tas de cachés (en commençant par le soulignement) les méthodes qui sont en charge du traitement complexe ou de bas niveau.

Je sais que les tests sont essentiels pour donner confiance au code et pour s'assurer que toute modification ultérieure n'a pas rompu le comportement précédent.

Problème:

Afin de construire les méthodes publiques de niveau supérieur sur une base fiable, je teste généralement les méthodes privées. Je trouve plus facile de savoir si une modification de code a introduit des régressions et où. Cela signifie que ces tests internes peuvent se casser sur des révisions mineures et devront être corrigés/remplacés

Mais je sais aussi que les tests unitaires de méthode privée sont au moins un concept contesté ou plus souvent considéré comme une mauvaise pratique. La raison étant: seul le comportement public doit être testé ( ref. )

Question:

Je tiens à suivre les meilleures pratiques et je voudrais comprendre:

  • pourquoi l'utilisation de tests unitaires sur des méthodes privées/cachées est-elle mauvaise (quel est le risque)?
  • quelles sont les meilleures pratiques lorsque les méthodes publiques peuvent utiliser un traitement de bas niveau et/ou complexe?

Précisions:

  • ce n'est pas comment question. Python n'a pas de véritable concept de confidentialité et les méthodes cachées ne sont tout simplement pas répertoriées mais peuvent être utilisées lorsque vous connaissez leur nom
  • Je n'ai jamais appris de règles et de modèles de programmation: mes derniers cours sont des années 80 ... J'ai principalement appris des langues par essais et échecs et des références sur Internet (Stack Exchange étant mon préféré depuis des années)
15
Serge Ballesta

Quelques raisons:

  1. Typiquement, lorsque vous êtes tenté de tester la méthode privée d'une classe, c'est une odeur de conception (classe iceberg, pas assez de composants publics réutilisables, etc.). Il y a presque toujours un problème "plus important" en jeu.

  2. Vous pouvez les tester via l'interface publique (c'est ainsi que vous voulez les tester, car c'est ainsi que le client les appellera/les utilisera). Vous pouvez obtenez un faux sentiment de sécurité en voyant le feu vert sur tous les tests réussis pour vos méthodes privées. Il est bien meilleur/plus sûr de tester les cas Edge sur vos fonctions privées via votre interface publique.

  3. Vous risquez une duplication sévère des tests (tests qui semblent très similaires) en testant des méthodes privées. Cela a des conséquences majeures lorsque les exigences changent, autant de tests que nécessaire se cassera. Cela peut également vous mettre dans une position où il est difficile de refactoriser à cause de votre suite de tests ... ce qui est l'ultime ironie, car la suite de tests est là pour vous aider à reconcevoir et à refaçonner en toute sécurité!

Un conseil si vous êtes toujours tenté de tester les parties privées (ne l'utilisez pas si cela vous dérange, et YMMV, mais cela a bien fonctionné pour moi dans le passé): Parfois, écrire des tests unitaires pour les fonctions privées juste pour s'assurer qu'elles fonctionnent exactement comment vous pensez qu'elles peuvent être utiles (surtout si vous êtes nouveau dans un langage) . Cependant, une fois que vous êtes sûr qu'ils fonctionnent, supprimez les tests et assurez-vous toujours que les tests faisant face à public sont solides et se bloqueront si quelqu'un apporte une modification flagrante à ladite fonction privée.

Quand tester des méthodes privées: Puisque cette réponse est devenue (quelque peu) populaire, je me sens obligé de mentionner qu'une "meilleure pratique" est toujours juste cela: une "meilleure pratique". Cela ne signifie pas que vous devez le faire de manière dogmatique ou aveugle. Si vous pensez que vous devriez tester vos méthodes privées et avoir une raison légitime (comme vous écrivez des tests de caractérisation pour une application héritée), puis testez vos méthodes privées. Circonstances spécifiques toujours l'emporte sur toute règle générale ou meilleure pratique. Soyez simplement conscient de certaines choses qui peuvent mal tourner (voir ci-dessus).

J'ai une réponse qui passe en revue cela en détail sur SO que je ne répéterai pas ici: https://stackoverflow.com/questions/105007/should-i-test -méthodes-privées-ou-seulement-publiques-47401015 # 47401015

17
Matt Messersmith

Étant donné que l'un des principaux objectifs des tests unitaires est que vous pouvez refactoriser les éléments internes de votre programme et ensuite être en mesure de vérifier que vous n'avez pas cassé sa fonctionnalité, il est contre-productif si vos tests unitaires fonctionnent à un niveau de granularité si fin que toute modification du code du programme vous oblige à réécrire vos tests.

13
Pete

Écriture de tests unitaires pour les méthodes privées lie vos tests unitaires aux détails d'implémentation.

Les tests unitaires doivent tester le comportement d'une classe à la surface extérieure de la classe (c'est l'API publique). Les tests unitaires ne devraient pas avoir à connaître les entrailles d'une classe. L'écriture de tests unitaires par rapport aux détails d'implémentation d'une classe vous lie quand vient le temps de refactoriser. Le refactoring va presque certainement casser ces tests, car ils ne font pas partie de votre API stable.

Cela dit, pourquoi pourriez-vous vouloir écrire des tests unitaires pour vos méthodes privées?

Il existe une tension naturelle entre les tests unitaires et le développement incrémentiel. Les développeurs de logiciels qui utilisent un REPL (boucle de lecture-évaluation-impression) peuvent attester de la productivité de l'écriture et du test rapides de petits morceaux de fonctionnalité à mesure que vous "développez" une classe ou une fonction. La seule bonne façon de le faire dans des environnements pilotés par des tests unitaires est d'écrire des tests unitaires pour des méthodes privées, mais il y a beaucoup de friction à le faire. Les tests unitaires prennent du temps à écrire, vous avez besoin d'une méthode réelle pour tester, et votre infrastructure de test doit prendre en charge la possibilité de garder la méthode privée afin qu'elle ne pollue pas votre API externe.

Certains écosystèmes comme C # et .NET ont des moyens de créer des environnements de type REPL (des outils tels que Linqpad le font), mais leur utilité est limitée car vous n'avez pas accès à votre projet. La fenêtre immédiate dans Visual Studio n'est pas pratique; il n'a toujours pas Intellisense complet, vous devez y utiliser des noms pleinement qualifiés et il déclenche une construction chaque fois que vous l'utilisez.

10
Robert Harvey

D'après mon expérience, j'ai découvert que le test unitaire des classes internes, des méthodes signifie généralement que je dois retirer les fonctions testées, les classes. Pour créer un autre niveau d'abstraction.

Cela conduit à une meilleure adhésion au principe de responsabilité unique.

6
Robert Andrzejuk

Je pense que c'est une bonne question car elle expose un problème commun dans les tests de couverture. Mais une bonne réponse devrait vous dire que la question n'est pas tout à fait correcte car, en théorie, vous devriez pas être en mesure de faire des tests unitaires privé méthodes. C'est pourquoi ils sont privés .

Peut-être qu'une meilleure question serait "Que dois-je faire quand je veux tester des méthodes privées?" , et la réponse est assez évidente: vous devriez exposer leur d'une manière qui rend les tests possibles. Maintenant, cela ne signifie pas nécessairement que vous devez simplement rendre la méthode publique et c'est tout. Vous voudrez probablement faire une abstraction plus élevée; passer à une autre bibliothèque ou API afin que vous puissiez effectuer vos tests sur cette bibliothèque, sans exposer cette fonctionnalité dans votre API principale.

N'oubliez pas qu'il y a une raison pour laquelle vos méthodes ont différents niveaux d'accessibilité, et vous devriez toujours penser à la façon dont vos classes seront utilisées à la fin.