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 méthodes cachées (en commençant par le soulignement) qui sont en charge de la 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 en est: seul le comportement public doit être testé ( réf. )
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 une question de savoir comment . 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)
la source
Réponses:
Quelques raisons:
Généralement, 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.
Vous pouvez les tester via l'interface publique (c'est ainsi que vous souhaitez les tester, car c'est ainsi que le client les appellera / les utilisera). Vous pouvez obtenir 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 beaucoup mieux / plus sûr de tester des cas de pointe sur vos fonctions privées via votre interface publique.
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, car il y aura beaucoup plus de tests que nécessaire. Il 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 des fonctions privées juste pour vous assurer ils fonctionnent exactement comme vous pensez qu'ils peuvent être utiles (surtout si vous êtes nouveau dans une langue). Cependant, une fois que vous êtes sûr qu'ils fonctionnent, supprimez les tests et assurez-vous toujours que les tests accessibles au 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), alors testez vos méthodes privées . Des circonstances spécifiques l'emportent toujours 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: /programming/105007/should-i-test-private-methods-or-only-public-ones/ 47401015 # 47401015
la source
bin_search(arr, item)
(public) etbin_search(arr, item, low, hi)
(privé, il y a plusieurs façons de faire une recherche dans le bac), alors tout ce dont vous avez besoin pour tester est le public face à un (bin_search(arr, item)
)É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.
la source
L'é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 voudriez - vous é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 une boucle REPL (lecture-évaluation-impression) peuvent attester à quel point il peut être productif d'écrire et de tester rapidement de petites fonctionnalités lorsque 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 effectuer des tests 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.
la source
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.
la source
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 ne devriez pas être en mesure de tester les méthodes privées de manière unitaire . 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 devez les exposer de manière à rendre 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.
la source