J'ai lu cet article sur la façon de tester des méthodes privées. Je ne les teste généralement pas, car j'ai toujours pensé qu'il était plus rapide de tester uniquement les méthodes publiques qui seront appelées de l'extérieur de l'objet. Testez-vous des méthodes privées? Dois-je toujours les tester?
unit-testing
testing
language-agnostic
Patrick Desjardins
la source
la source
Réponses:
Je ne fais pas de tests unitaires sur les méthodes privées. Une méthode privée est un détail d'implémentation qui doit être caché aux utilisateurs de la classe. Le test des méthodes privées interrompt l'encapsulation.
Si je trouve que la méthode privée est énorme ou complexe ou suffisamment importante pour nécessiter ses propres tests, je la mets simplement dans une autre classe et la rend publique là-bas ( objet méthode ). Ensuite, je peux facilement tester la méthode auparavant privée mais maintenant publique qui vit maintenant dans sa propre classe.
la source
Quel est le but des tests?
Jusqu'à présent, la majorité des réponses disent que les méthodes privées sont des détails d'implémentation qui n'ont pas (ou du moins ne devraient pas) d'importance tant que l'interface publique est bien testée et fonctionne. C'est tout à fait correct si votre seul objectif de test est de garantir le fonctionnement de l'interface publique .
Personnellement, ma principale utilisation pour les tests de code est de garantir que les modifications futures du code ne causent pas de problèmes et d'aider mes efforts de débogage s'ils le font. Je trouve que tester les méthodes privées aussi minutieusement que l'interface publique (sinon plus!) Sert cet objectif.
Considérez: Vous avez la méthode publique A qui appelle la méthode privée B. A et B utilisent tous deux la méthode C. C est modifié (peut-être par vous, peut-être par un fournisseur), ce qui fait que A commence à échouer ses tests. Ne serait-il pas utile d'avoir des tests pour B également, même s'ils sont privés, afin de savoir si le problème est lié à l'utilisation de C par A, à l'utilisation de C par B, ou aux deux?
Les tests de méthodes privées ajoutent également de la valeur dans les cas où la couverture des tests de l'interface publique est incomplète. Bien que ce soit une situation que nous souhaitons généralement éviter, les tests d'unité d'efficacité dépendent à la fois des tests de recherche de bogues et des coûts de développement et de maintenance associés à ces tests. Dans certains cas, les avantages d'une couverture de test à 100% peuvent être jugés insuffisants pour justifier les coûts de ces tests, créant des lacunes dans la couverture de test de l'interface publique. Dans de tels cas, un test bien ciblé d'une méthode privée peut être un ajout très efficace à la base de code.
la source
testDoSomething()
outestDoSomethingPrivate()
. Cela rend le test moins valable. . Voici plus de raisons pour tester privé stackoverflow.com/questions/34571/… :J'ai tendance à suivre les conseils de Dave Thomas et Andy Hunt dans leur livre Pragmatic Unit Testing :
Mais parfois, je ne peux pas m'empêcher de tester des méthodes privées car cela me rassure que je construis un programme complètement robuste.
la source
Je me sens un peu obligé de tester des fonctions privées car je suis de plus en plus l'une de nos dernières recommandations QA dans notre projet:
Maintenant, l'effet secondaire de l'application de cette politique est que beaucoup de mes très grandes fonctions publiques sont divisées en de nombreuses fonctions privées plus ciblées et mieux nommées .
La fonction publique est toujours là (bien sûr) mais est essentiellement réduite à toutes ces «sous-fonctions» privées
C'est vraiment cool, car la pile d'appels est maintenant beaucoup plus facile à lire (au lieu d'un bogue dans une grande fonction, j'ai un bogue dans une sous-sous-fonction avec le nom des fonctions précédentes dans la pile d'appels pour m'aider à comprendre 'comment j'y suis arrivé')
Cependant, il semble maintenant plus facile de tester directement ces fonctions privées et de laisser le test de la grande fonction publique à une sorte de test «d'intégration» où un scénario doit être traité.
Juste mes 2 cents.
la source
Oui, je teste des fonctions privées, car bien qu'elles soient testées par vos méthodes publiques, il est agréable dans TDD (Test Driven Design) de tester la plus petite partie de l'application. Mais les fonctions privées ne sont pas accessibles lorsque vous êtes dans votre classe d'unité de test. Voici ce que nous faisons pour tester nos méthodes privées.
Pourquoi avons-nous des méthodes privées?
Les fonctions privées existent principalement dans notre classe car nous voulons créer du code lisible dans nos méthodes publiques. Nous ne voulons pas que l'utilisateur de cette classe appelle ces méthodes directement, mais via nos méthodes publiques. De plus, nous ne voulons pas changer leur comportement lors de l'extension de la classe (en cas de protection), c'est donc un privé.
Lorsque nous codons, nous utilisons la conception pilotée par les tests (TDD). Cela signifie que parfois nous tombons sur une fonctionnalité privée et que nous voulons tester. Les fonctions privées ne sont pas testables dans phpUnit, car nous ne pouvons pas y accéder dans la classe Test (elles sont privées).
Nous pensons que voici 3 solutions:
1. Vous pouvez tester vos privés grâce à vos méthodes publiques
Les avantages
Désavantages
2. Si le privé est si important, alors peut-être que c'est un code pour créer une nouvelle classe séparée pour lui
Les avantages
Désavantages
3. Changez le modificateur d'accès en (final) protégé
Les avantages
Désavantages
Exemple
Notre unité de test peut donc maintenant appeler test_sleepWithSuspect pour tester notre ancienne fonction privée.
la source
Je n'aime pas tester les fonctionnalités privées pour plusieurs raisons. Ils sont les suivants (ce sont les principaux points pour les personnes TLDR):
Je vais expliquer chacun d'eux avec un exemple concret. Il s'avère que 2) et 3) sont quelque peu intimement liés, donc leur exemple est similaire, bien que je les considère comme des raisons distinctes pour lesquelles vous ne devriez pas tester des méthodes privées.
Il est parfois nécessaire de tester des méthodes privées, il est juste important d'être conscient des inconvénients énumérés ci-dessus. Je vais l'examiner plus en détail plus tard.
Je passe également en revue pourquoi TDD n'est pas une excuse valable pour tester des méthodes privées à la toute fin.
Refactorisation de votre sortie d'un mauvais design
L'un des paternités (anti) les plus courantes que je vois est ce que Michael Feathers appelle une classe "Iceberg" (si vous ne savez pas qui est Michael Feathers, allez acheter / lire son livre "Working Effectively with Legacy Code". Il est une personne à savoir si vous êtes un ingénieur / développeur de logiciels professionnel). Il existe d'autres modèles (anti) qui provoquent ce problème, mais c'est de loin le plus courant que j'ai rencontré. Les classes "Iceberg" ont une méthode publique, et les autres sont privées (c'est pourquoi il est tentant de tester les méthodes privées). Cela s'appelle une classe "Iceberg" car il y a généralement une méthode publique solitaire, mais le reste de la fonctionnalité est caché sous l'eau sous forme de méthodes privées.
Par exemple, vous pourriez vouloir tester
GetNextToken()
en l'appelant successivement sur une chaîne et en voyant qu'il renvoie le résultat attendu. Une fonction comme celle-ci mérite un test: ce comportement n'est pas anodin, surtout si vos règles de tokenisation sont complexes. Imaginons que ce ne soit pas si complexe, et nous voulons simplement enchaîner des jetons délimités par l'espace. Donc, vous écrivez un test, peut-être qu'il ressemble à quelque chose comme ça (un pseudo-code indépendant du langage, j'espère que l'idée est claire):Eh bien, ça a l'air plutôt sympa. Nous souhaitons nous assurer de conserver ce comportement lorsque nous apportons des modifications. Mais
GetNextToken()
c'est une fonction privée ! Nous ne pouvons donc pas le tester comme ceci, car il ne compilera même pas (en supposant que nous utilisons un langage qui applique réellement public / privé, contrairement à certains langages de script comme Python). Mais qu'en est-il du changement deRuleEvaluator
classe pour suivre le principe de responsabilité unique (principe de responsabilité unique)? Par exemple, nous semblons avoir un analyseur, un tokenizer et un évaluateur coincés dans une seule classe. Ne serait-il pas préférable de simplement séparer ces responsabilités? En plus de cela, si vous créez uneTokenizer
classe, ses méthodes publiques seraientHasMoreTokens()
etGetNextTokens()
. LaRuleEvaluator
classe pourrait avoir unTokenizer
objet en tant que membre. Maintenant, nous pouvons garder le même test que ci-dessus, sauf que nous testons laTokenizer
classe au lieu de laRuleEvaluator
classe.Voici à quoi cela pourrait ressembler en UML:
Notez que cette nouvelle conception augmente la modularité, vous pouvez donc potentiellement réutiliser ces classes dans d'autres parties de votre système (avant vous, les méthodes privées ne sont pas réutilisables par définition). C'est le principal avantage de décomposer l'évaluateur de règles, ainsi qu'une meilleure compréhensibilité / localité.
Le test serait extrêmement similaire, sauf qu'il se compilerait cette fois puisque la
GetNextToken()
méthode est maintenant publique sur laTokenizer
classe:Tester des composants privés via une interface publique et éviter la duplication des tests
Même si vous ne pensez pas pouvoir décomposer votre problème en moins de composants modulaires (ce que vous pouvez faire 95% du temps si vous essayez de le faire), vous pouvez simplement tester les fonctions privées via une interface publique. Plusieurs fois, les membres privés ne valent pas la peine d'être testés car ils seront testés via l'interface publique. Souvent, ce que je vois, ce sont des tests qui se ressemblent beaucoup , mais testez deux fonctions / méthodes différentes. Ce qui finit par arriver, c'est que lorsque les exigences changent (et elles le font toujours), vous avez maintenant 2 tests cassés au lieu de 1. Et si vous avez vraiment testé toutes vos méthodes privées, vous pourriez avoir plus de 10 tests cassés au lieu de 1. En bref , tester des fonctions privées (en utilisant
FRIEND_TEST
ou les rendre publics ou en utilisant la réflexion) qui pourraient autrement être testés via une interface publique peuvent entraîner la duplication des tests et / ou de réflexion, vous finirez généralement par le regretter à long terme.. Vous ne voulez vraiment pas cela, car rien ne fait plus mal que votre suite de tests qui vous ralentit. Il est censé réduire le temps de développement et les coûts de maintenance! Si vous testez des méthodes privées qui sont autrement testées via une interface publique, la suite de tests peut très bien faire le contraire, et augmenter activement les coûts de maintenance et augmenter le temps de développement. Lorsque vous rendez une fonction privée publique, ou si vous utilisez quelque chose commeFRIEND_TEST
Considérez l'implémentation possible suivante de la
Tokenizer
classe:Disons que
SplitUpByDelimiter()
c'est responsable du retour d'un tableau tel que chaque élément du tableau est un jeton. De plus, disons simplement queGetNextToken()
c'est simplement un itérateur sur ce vecteur. Ainsi, votre test public pourrait ressembler à ceci:Imaginons que nous ayons ce que Michael Feather appelle un outil de tâtonnement . Il s'agit d'un outil qui vous permet de toucher les parties intimes des autres. Un exemple est
FRIEND_TEST
de googletest, ou de réflexion si la langue le supporte.Eh bien, disons maintenant que les exigences changent et que la tokenisation devient beaucoup plus complexe. Vous décidez qu'un simple délimiteur de chaîne ne suffira pas et vous avez besoin d'une
Delimiter
classe pour gérer le travail. Naturellement, vous vous attendez à ce qu'un test se brise, mais cette douleur augmente lorsque vous testez des fonctions privées.Quand les tests de méthodes privées peuvent-ils être appropriés?
Il n'y a pas de "solution unique" dans le logiciel. Parfois, c'est correct (et en fait idéal) de "briser les règles". Je recommande fortement de ne pas tester les fonctionnalités privées lorsque vous le pouvez. Il y a deux situations principales quand je pense que ça va:
J'ai beaucoup travaillé avec les systèmes hérités (c'est pourquoi je suis un grand fan de Michael Feathers), et je peux dire en toute sécurité qu'il est parfois tout simplement plus sûr de simplement tester la fonctionnalité privée. Il peut être particulièrement utile pour obtenir des «tests de caractérisation» dans la ligne de base.
Vous êtes pressé et devez faire la chose la plus rapide possible ici et maintenant. À long terme, vous ne voulez pas tester des méthodes privées. Mais je dirai qu'il faut généralement un certain temps pour refactoriser les problèmes de conception. Et parfois, vous devez expédier dans une semaine. Ce n'est pas grave: faites vite et sale et testez les méthodes privées à l'aide d'un outil de tâtonnement si c'est ce que vous pensez être le moyen le plus rapide et le plus fiable pour faire le travail. Mais comprenez que ce que vous avez fait n'était pas optimal à long terme, et pensez à y revenir (ou, s'il a été oublié mais que vous le voyez plus tard, corrigez-le).
Il y a probablement d'autres situations où ça va. Si vous pensez que tout va bien et que vous avez une bonne justification, faites-le. Personne ne vous arrête. Soyez juste conscient des coûts potentiels.
L'excuse TDD
En passant, je n'aime vraiment pas que les gens utilisent TDD comme excuse pour tester des méthodes privées. Je pratique le TDD et je ne pense pas que le TDD vous oblige à le faire. Vous pouvez d'abord écrire votre test (pour votre interface publique), puis écrire du code pour satisfaire cette interface. Parfois, j'écris un test pour une interface publique, et je le satisfait en écrivant également une ou deux méthodes privées plus petites (mais je ne teste pas directement les méthodes privées, mais je sais qu'elles fonctionnent ou mon test public échouerait) ). Si je dois tester des cas limites de cette méthode privée, j'écrirai tout un tas de tests qui les atteindront via mon interface publique.Si vous ne savez pas comment frapper les cas extrêmes, c'est un signe fort que vous devez refactoriser en petits composants chacun avec leurs propres méthodes publiques. C'est un signe que vos fonctions privées en font trop et sortent du cadre de la classe .
De plus, parfois je trouve que j'écris un test qui est trop gros pour mordre pour le moment, et donc je pense "eh je reviendrai à ce test plus tard quand j'aurai plus d'une API pour travailler" (je Je vais le commenter et le garder dans le fond de mon esprit). C'est là que de nombreux développeurs que j'ai rencontrés commenceront alors à écrire des tests pour leurs fonctionnalités privées, en utilisant TDD comme bouc émissaire. Ils disent "oh, eh bien j'ai besoin d'un autre test, mais pour écrire ce test, j'ai besoin de ces méthodes privées. Par conséquent, comme je ne peux pas écrire de code de production sans écrire un test, j'ai besoin d'écrire un test pour une méthode privée. " Mais ce qu'ils doivent vraiment faire, c'est refactoriser en composants plus petits et réutilisables au lieu d'ajouter / tester un tas de méthodes privées à leur classe actuelle.
Remarque:
Il y a quelques temps, j'ai répondu à une question similaire sur le test de méthodes privées à l'aide de GoogleTest . J'ai surtout modifié cette réponse pour être plus indépendant de la langue ici.
PS Voici la conférence pertinente sur les classes d'iceberg et les outils de tâtonnement de Michael Feathers: https://www.youtube.com/watch?v=4cVZvoFGJTU
la source
_
, cela indique "hé, c'est" privé ". Vous pouvez l'utiliser, mais la divulgation complète, il n'a pas été conçu pour être réutilisé et vous ne devez l'utiliser que si vous vraiment savoir ce que vous faites ". Vous pouvez adopter la même approche dans n'importe quelle langue: rendre ces membres publics, mais marquez-les avec un leader_
. Ou peut-être que ces fonctions devraient vraiment être privées et simplement testées via une interface publique (voir la réponse pour plus de détails). C'est au cas par cas, pas de règle généraleJe pense qu'il est préférable de simplement tester l'interface publique d'un objet. Du point de vue du monde extérieur, seul le comportement de l'interface publique est important et c'est vers cela que vos tests unitaires doivent être orientés.
Une fois que vous avez écrit des tests unitaires solides pour un objet, vous ne voulez pas avoir à revenir en arrière et à modifier ces tests simplement parce que l'implémentation derrière l'interface a changé. Dans cette situation, vous avez ruiné la cohérence de vos tests unitaires.
la source
Si votre méthode privée n'est pas testée en appelant vos méthodes publiques, que fait-elle? Je parle privé non protégé ou ami.
la source
Si la méthode privée est bien définie (c'est-à-dire qu'elle a une fonction qui peut être testée et n'est pas censée changer au fil du temps), alors oui. Je teste tout ce qui est testable là où cela a du sens.
Par exemple, une bibliothèque de chiffrement peut masquer le fait qu'elle effectue un chiffrement par blocs avec une méthode privée qui ne chiffre que 8 octets à la fois. J'écrirais un test unitaire pour cela - ce n'est pas censé changer, même s'il est caché, et s'il se casse (en raison des améliorations futures des performances, par exemple), alors je veux savoir que c'est la fonction privée qui a cassé, pas seulement que l'une des fonctions publiques a éclaté.
Il accélère le débogage plus tard.
-Adam
la source
Si vous développez piloté par les tests (TDD), vous testerez vos méthodes privées.
la source
Je ne suis pas un expert dans ce domaine, mais les tests unitaires devraient tester le comportement, pas la mise en œuvre. Les méthodes privées font strictement partie de la mise en œuvre, donc IMHO ne doit pas être testé.
la source
Nous testons les méthodes privées par inférence, ce qui signifie que nous recherchons une couverture de test de classe totale d'au moins 95%, mais que nos tests ne font appel qu'à des méthodes publiques ou internes. Pour obtenir la couverture, nous devons effectuer plusieurs appels au public / internes en fonction des différents scénarios qui peuvent se produire. Cela rend nos tests plus attentifs à l'objectif du code qu'ils testent.
La réponse de Trumpi au message que vous avez lié est la meilleure.
la source
Les tests unitaires sont, je crois, destinés à tester des méthodes publiques. Vos méthodes publiques utilisent vos méthodes privées, donc indirectement elles sont également testées.
la source
Je réfléchis à ce problème depuis un certain temps, en particulier en essayant le TDD.
Je suis tombé sur deux articles qui, je pense, résolvent ce problème de manière suffisamment approfondie dans le cas de TDD.
En résumé:
Lorsque vous utilisez des techniques de développement (conception) pilotées par les tests, les méthodes privées ne doivent apparaître que pendant le processus de refactorisation du code déjà fonctionnel et testé.
De par la nature même du processus, tout élément de fonctionnalité d'implémentation simple extrait d'une fonction soigneusement testée sera lui-même testé (c'est-à-dire la couverture des tests indirects).
Pour moi, il semble assez clair qu'au début, la plupart des méthodes de codage seront des fonctions de niveau supérieur car elles encapsulent / décrivent la conception.
Par conséquent, ces méthodes seront publiques et les tester sera assez facile.
Les méthodes privées viendront plus tard une fois que tout fonctionne bien et nous refactorisons pour des raisons de lisibilité et de propreté .
la source
Comme cité ci-dessus, "Si vous ne testez pas vos méthodes privées, comment savez-vous qu'elles ne se casseront pas?"
C'est un problème majeur. L'un des grands points des tests unitaires est de savoir où, quand et comment quelque chose s'est cassé dès que possible. Diminuant ainsi une quantité importante d'efforts de développement et d'assurance qualité. Si tout ce qui est testé est le public, alors vous n'avez pas une couverture et une délimitation honnêtes des internes de la classe.
J'ai trouvé l'une des meilleures façons de le faire, il suffit d'ajouter la référence de test au projet et de placer les tests dans une classe parallèle aux méthodes privées. Mettez la logique de construction appropriée afin que les tests ne soient pas intégrés dans le projet final.
Ensuite, vous avez tous les avantages de tester ces méthodes et vous pouvez trouver des problèmes en quelques secondes par rapport aux minutes ou aux heures.
Donc en résumé, oui, testez à l'unité vos méthodes privées.
la source
Tu ne devrais pas . Si vos méthodes privées ont suffisamment de complexité à tester, vous devez les mettre dans une autre classe. Gardez une cohésion élevée , une classe ne devrait avoir qu'un seul but. L'interface publique de classe devrait être suffisante.
la source
Si vous ne testez pas vos méthodes privées, comment savez-vous qu'elles ne casseront pas?
la source
Cela dépend évidemment de la langue. Dans le passé avec c ++, j'ai déclaré que la classe testing était une classe amie. Malheureusement, cela nécessite que votre code de production connaisse la classe de test.
la source
Je comprends le point de vue où les méthodes privées sont considérées comme des détails d'implémentation et n'ont donc pas à être testées. Et je m'en tiendrais à cette règle si nous devions nous développer en dehors de l'objet uniquement. Mais nous, sommes-nous une sorte de développeurs restreints qui ne développent qu'en dehors des objets, en appelant uniquement leurs méthodes publiques? Ou développons-nous également cet objet? Comme nous ne sommes pas tenus de programmer des objets extérieurs, nous devrons probablement appeler ces méthodes privées dans de nouvelles méthodes publiques que nous développons. Ne serait-il pas formidable de savoir que la méthode privée résiste contre toute attente?
Je sais que certaines personnes pourraient répondre que si nous développons une autre méthode publique dans cet objet, alors celle-ci devrait être testée et c'est tout (la méthode privée pourrait continuer à vivre sans test). Mais cela est également vrai pour toutes les méthodes publiques d'un objet: lors du développement d'une application web, toutes les méthodes publiques d'un objet sont appelées à partir des méthodes des contrôleurs et peuvent donc être considérées comme des détails d'implémentation pour les contrôleurs.
Alors pourquoi faisons-nous des tests unitaires sur les objets? Parce que c'est vraiment difficile, pour ne pas dire impossible d'être sûr que nous testons les méthodes des contrôleurs avec l'entrée appropriée qui déclenchera toutes les branches du code sous-jacent. En d'autres termes, plus nous sommes élevés dans la pile, plus il est difficile de tester tout le comportement. Et il en va de même pour les méthodes privées.
Pour moi, la frontière entre les méthodes privées et publiques est un critère psychologique en matière de tests. Les critères qui m'importent le plus sont:
la source
Si je trouve que la méthode privée est énorme ou complexe ou suffisamment importante pour nécessiter ses propres tests, je la mets simplement dans une autre classe et la rend publique là-bas (objet méthode). Ensuite, je peux facilement tester la méthode auparavant privée mais maintenant publique qui vit maintenant dans sa propre classe.
la source
Je ne comprends jamais le concept de test unitaire mais maintenant je sais quel est l'objectif.
Un test unitaire n'est pas un test complet . Donc, ce n'est pas un remplacement pour le contrôle qualité et le test manuel. Le concept de TDD dans cet aspect est faux car vous ne pouvez pas tout tester, y compris les méthodes privées mais aussi les méthodes qui utilisent des ressources (en particulier des ressources que nous n'avons pas de contrôle). TDD fonde toute sa qualité sur quelque chose qu'il n'a pas pu atteindre.
Un test unitaire est plus un test de pivot. Vous marquez un pivot arbitraire et le résultat du pivot doit rester le même.
la source
Public vs privé n'est pas une distinction utile pour ce que les API doivent appeler à partir de vos tests, pas plus que la méthode ou la classe. La plupart des unités testables sont visibles dans un contexte, mais cachées dans d'autres.
Ce qui compte, c'est la couverture et les coûts. Vous devez minimiser les coûts tout en atteignant les objectifs de couverture de votre projet (ligne, branche, chemin, bloc, méthode, classe, classe d'équivalence, cas d'utilisation ... quoi que l'équipe décide).
Utilisez donc des outils pour assurer la couverture et concevez vos tests pour réduire les coûts (à court et à long terme ).
Ne faites pas les tests plus chers que nécessaire. S'il est le moins cher de ne tester que les points d'entrée publics, faites-le. S'il est moins cher de tester des méthodes privées, faites-le.
Au fur et à mesure que vous devenez plus expérimenté, vous deviendrez de mieux en mieux prédire quand cela vaut la peine d'être refactorisé pour éviter les coûts à long terme de la maintenance des tests.
la source
Si la méthode est suffisamment importante / assez complexe, je la fais généralement "protégée" et la teste. Certaines méthodes resteront privées et testées implicitement dans le cadre de tests unitaires pour les méthodes publiques / protégées.
la source
Je vois que beaucoup de gens sont dans la même ligne de pensée: tester au niveau public. mais n'est-ce pas ce que fait notre équipe QA? Ils testent l'entrée et la sortie attendue. Si en tant que développeurs, nous testons uniquement les méthodes publiques, nous refaisons simplement le travail de QA et n'ajoutons aucune valeur par des «tests unitaires».
la source
La réponse à "Dois-je tester des méthodes privées?" est parfois". En règle générale, vous devez tester par rapport à l'interface de vos classes.
Voici un exemple:
En
RefactoredThing
vous maintenant 5 tests, dont 2 vous deviez mettre à jour pour refactoring, mais la fonctionnalité de votre objet n'a pas vraiment changé. Disons donc que les choses sont plus complexes que cela et que vous avez une méthode qui définit l'ordre de la sortie, comme:Cela ne devrait pas être exécuté par un utilisateur externe, mais votre classe d'encapsulation peut être trop lourde pour exécuter autant de logique à travers elle encore et encore. Dans ce cas, vous préférez peut-être extraire cela dans une classe distincte, donner à cette classe une interface et la tester.
Et enfin, disons que votre objet principal est super lourd, et la méthode est assez petite et vous devez vraiment vous assurer que la sortie est correcte. Vous pensez: "Je dois tester cette méthode privée!". Avez-vous que vous pourriez peut-être rendre votre objet plus léger en passant une partie du travail lourd comme paramètre d'initialisation? Ensuite, vous pouvez passer quelque chose de plus léger et tester contre cela.
la source
Non Vous ne devriez pas tester les méthodes privées pourquoi? De plus, le framework de simulation populaire tel que Mockito ne prend pas en charge le test des méthodes privées.
la source
Un point principal est
Si nous testons pour garantir l'exactitude de la logique, et qu'une méthode privée porte une logique, nous devons la tester. N'est-ce pas? Alors pourquoi allons-nous sauter cela?
La rédaction de tests basés sur la visibilité des méthodes est une idée totalement hors de propos.
inversement
D'un autre côté, appeler une méthode privée en dehors de la classe d'origine est un problème majeur. Et il y a aussi des limitations pour se moquer d'une méthode privée dans certains outils de simulation. (Ex: Mockito )
Bien qu'il existe des outils comme Power Mock qui prennent en charge cela, c'est une opération dangereuse. La raison en est qu'il doit pirater la JVM pour y parvenir.
Une solution à ce problème peut être (si vous voulez écrire des cas de test pour des méthodes privées)
Déclarez ces méthodes privées protégées . Mais cela peut ne pas convenir à plusieurs situations.
la source
Il ne s'agit pas seulement de méthodes ou de fonctions publiques ou privées, il s'agit de détails d'implémentation. Les fonctions privées ne sont qu'un aspect des détails de mise en œuvre.
Le test unitaire, après tout, est une approche de test en boîte blanche. Par exemple, quiconque utilise l'analyse de couverture pour identifier les parties du code qui ont été négligées jusqu'à présent dans les tests, entre dans les détails de l'implémentation.
A) Oui, vous devriez tester les détails de mise en œuvre:
Pensez à une fonction de tri qui, pour des raisons de performances, utilise une implémentation privée de BubbleSort s'il y a jusqu'à 10 éléments, et une implémentation privée d'une approche de tri différente (disons, heapsort) s'il y a plus de 10 éléments. L'API publique est celle d'une fonction de tri. Cependant, votre suite de tests utilise mieux les connaissances selon lesquelles il existe en fait deux algorithmes de tri.
Dans cet exemple, vous pourriez sûrement effectuer les tests sur l'API publique. Cela nécessiterait, cependant, d'avoir un certain nombre de cas de test qui exécutent la fonction de tri avec plus de 10 éléments, de sorte que l'algorithme de tri sélectif soit suffisamment bien testé. L'existence de tels cas de test seuls indique que la suite de tests est connectée aux détails d'implémentation de la fonction.
Si les détails d'implémentation de la fonction de tri changent, peut-être de la manière dont la limite entre les deux algorithmes de tri est décalée ou que le tri par tas est remplacé par mergesort ou autre: les tests existants continueront de fonctionner. Leur valeur est néanmoins discutable, et ils doivent probablement être retravaillés pour mieux tester la fonction de tri modifiée. En d'autres termes, il y aura un effort de maintenance malgré le fait que les tests étaient sur l'API publique.
B) Comment tester les détails de l'implémentation
Une raison pour laquelle de nombreuses personnes soutiennent qu'il ne faut pas tester les fonctions privées ou les détails d'implémentation est que les détails d'implémentation sont plus susceptibles de changer. Cette probabilité plus élevée de changement au moins est l'une des raisons pour lesquelles les détails d'implémentation sont masqués derrière les interfaces.
Supposons maintenant que l'implémentation derrière l'interface contient des parties privées plus grandes pour lesquelles des tests individuels sur l'interface interne peuvent être une option. Certaines personnes soutiennent que ces parties ne doivent pas être testées lorsqu'elles sont privées, elles doivent être transformées en quelque chose de public. Une fois rendu public, le test unitaire de ce code serait OK.
C'est intéressant: bien que l'interface soit interne, elle était susceptible de changer, étant un détail d'implémentation. Prendre la même interface, la rendre publique fait une transformation magique, à savoir la transformer en une interface moins susceptible de changer. De toute évidence, il y a une faille dans cette argumentation.
Mais il y a néanmoins une part de vérité derrière cela: lors du test des détails d'implémentation, en particulier à l'aide d'interfaces internes, il faut s'efforcer d'utiliser des interfaces susceptibles de rester stables. Cependant, le fait de savoir si une interface est susceptible d'être stable n'est pas simplement décidable selon qu'elle est publique ou privée. Dans les projets du monde dans lesquels je travaille depuis un certain temps, les interfaces publiques changent aussi assez souvent et de nombreuses interfaces privées sont restées intactes depuis des lustres.
Pourtant, c'est une bonne règle de base d'utiliser la "porte d'entrée en premier" (voir http://xunitpatterns.com/Principles%20of%20Test%20Automation.html ). Mais gardez à l'esprit qu'elle est appelée "porte d'entrée en premier" et non "porte d'entrée uniquement".
C) Résumé
Testez également les détails d'implémentation. Préférez les tests sur des interfaces stables (publiques ou privées). Si les détails de l'implémentation changent, les tests sur l'API publique doivent également être révisés. Transformer quelque chose de privé en public ne change pas comme par magie sa stabilité.
la source
Oui, dans la mesure du possible, vous devez tester des méthodes privées. Pourquoi? Pour éviter une explosion inutile de l'espace d'état des cas de test qui finissent par se retrouver implicitement à tester de manière répétée les mêmes fonctions privées sur les mêmes entrées. Expliquons pourquoi avec un exemple.
Prenons l'exemple légèrement artificiel suivant. Supposons que nous voulons exposer publiquement une fonction qui prend 3 entiers et retourne vrai si et seulement si ces 3 entiers sont tous premiers. Nous pourrions l'implémenter comme ceci:
Maintenant, si nous devions adopter l'approche stricte selon laquelle seules les fonctions publiques devraient être testées, nous ne serions autorisés qu'à tester
allPrime
et nonisPrime
ouandAll
.En tant que testeur, nous pourrions être intéressés à cinq possibilités pour chaque argument:
< 0
,= 0
,= 1
,prime > 1
,not prime > 1
. Mais pour être approfondi, nous devons également voir comment chaque combinaison d'arguments se joue ensemble. Donc, c'est5*5*5
= 125 cas de test dont nous aurions besoin pour tester minutieusement cette fonction, selon nos intuitions.En revanche, si nous étions autorisés à tester les fonctions privées, nous pourrions couvrir autant de terrain avec moins de cas de test. Nous n'aurions besoin que de 5 cas de test
isPrime
pour tester au même niveau que notre intuition précédente. Et par l' hypothèse de petite portée proposée par Daniel Jackson, nous n'aurions besoin que de tester laandAll
fonction jusqu'à une petite longueur, par exemple 3 ou 4. Ce serait au plus 16 tests supplémentaires. Donc 21 tests au total. Au lieu de 125. Bien sûr, nous voudrions probablement effectuer quelques testsallPrime
, mais nous ne nous sentirions pas obligés de couvrir de manière exhaustive toutes les 125 combinaisons de scénarios d'entrée dont nous avons dit que nous nous soucions de nous. Juste quelques chemins heureux.Un exemple artificiel, bien sûr, mais il était nécessaire pour une démonstration claire. Et le modèle s'étend aux vrais logiciels. Les fonctions privées sont généralement les blocs de construction de niveau le plus bas, et sont donc souvent combinées ensemble pour produire une logique de niveau supérieur. Ce qui signifie à des niveaux plus élevés, nous avons plus de répétitions des choses de niveau inférieur en raison des diverses combinaisons.
la source
isPrime
sont vraiment indépendants, donc tester aveuglément chaque combinaison est assez inutile. Deuxièmement, le marquage d'une fonction pure appeléeisPrime
privée viole tellement de règles de conception que je ne sais même pas par où commencer.isPrime
devrait très clairement être une fonction publique. Cela étant dit, je comprends ce que vous dites, quel que soit cet exemple extrêmement médiocre. Cependant , il est construit au large de la prémisse que vous auriez voulez faire des tests de combinaison, lorsque dans les systèmes logiciels réels , cela est rarement une bonne idée.Vous pouvez également rendre votre méthode package-privée, c'est-à-dire par défaut et vous devriez pouvoir la tester à l'unité, sauf si elle doit être privée.
la source