Question Comment tester une fonction privée ou une classe qui a des méthodes privées, des champs ou des classes internes?


Comment puis-je tester (à l'aide de xUnit) une classe qui a des méthodes privées internes, des champs ou des classes imbriquées? Ou une fonction qui est rendue privée en ayant liaison interne (static en C / C ++) ou est privé (anonyme) espace de noms?

Il semble mauvais de changer le modificateur d'accès pour une méthode ou une fonction juste pour pouvoir exécuter un test.


2265


origine


Réponses:


Si vous avez un peu d'héritage Java application, et vous n'êtes pas autorisé à modifier la visibilité de vos méthodes, la meilleure façon de tester des méthodes privées est d'utiliser réflexion.

En interne, nous utilisons des aides pour obtenir / définir private et private static variables ainsi que invoquer private et private static méthodes Les modèles suivants vous permettront de faire à peu près tout ce qui concerne les méthodes et champs privés. Bien sûr, vous ne pouvez pas changer private static final variables à travers la réflexion.

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

Et pour les champs:

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

Remarques:
  1. targetClass.getDeclaredMethod(methodName, argClasses) vous permet de regarder dans private méthodes La même chose s'applique pour    getDeclaredField.
  2. Le setAccessible(true) est nécessaire pour jouer avec des soldats.


1416



La meilleure façon de tester une méthode privée consiste à utiliser une autre méthode publique. Si cela ne peut pas être fait, alors l'une des conditions suivantes est vraie:

  1. La méthode privée est le code mort
  2. Il y a une odeur de design près de la classe que vous testez
  3. La méthode que vous essayez de tester ne doit pas être privée

506



Quand j'ai des méthodes privées dans une classe qui sont suffisamment compliquées pour que je ressente le besoin de tester directement les méthodes privées, c'est une odeur de code: ma classe est trop compliquée.

Mon approche habituelle pour résoudre ces problèmes consiste à créer une nouvelle classe contenant les éléments intéressants. Souvent, cette méthode et les champs avec lesquels elle interagit, et peut-être une autre méthode ou deux peuvent être extraits dans une nouvelle classe.

La nouvelle classe expose ces méthodes en tant que 'public', elles sont donc accessibles pour les tests unitaires. Les classes nouvelles et anciennes sont maintenant plus simples que la classe originale, ce qui est super pour moi (j'ai besoin de garder les choses simples, ou je me perds!).

Notez que je ne suggère pas que les gens créent des classes sans utiliser leur cerveau! Le point ici est d'utiliser les forces des tests unitaires pour vous aider à trouver de bonnes nouvelles classes.


271



j'ai utilisé réflexion pour faire cela pour Java dans le passé, et à mon avis c'était une grosse erreur.

Strictement parlant, vous devriez ne pas écrire des tests unitaires qui testent directement des méthodes privées. Ce que tu devrait tester est le contrat public que la classe a avec d'autres objets; vous ne devriez jamais tester directement les internes d'un objet. Si un autre développeur souhaite apporter un petit changement interne à la classe, ce qui n'affecte pas le contrat public des classes, il doit alors modifier votre test basé sur la réflexion pour s'assurer que cela fonctionne. Si vous le faites de manière répétée tout au long d'un projet, les tests unitaires cessent alors d'être une mesure utile de la santé du code, et commencent à devenir un obstacle au développement, et un désagrément pour l'équipe de développement.

Ce que je recommande de faire à la place est d'utiliser un outil de couverture de code tel que Cobertura, pour s'assurer que les tests unitaires que vous écrivez fournissent une couverture décente du code dans des méthodes privées. De cette façon, vous testez indirectement ce que font les méthodes privées et maintenez un niveau d'agilité supérieur.


229



De cet article: Test de méthodes privées avec JUnit et SuiteRunner (Bill Venners), vous avez essentiellement 4 options:

  • Ne pas tester les méthodes privées.
  • Donnez l'accès au package de méthodes.
  • Utilisez une classe de test imbriquée.
  • Utilisez la réflexion.

187



Généralement, un test unitaire est destiné à exercer l'interface publique d'une classe ou d'une unité. Par conséquent, les méthodes privées sont des détails d'implémentation que vous ne souhaitez pas tester explicitement.


96



Juste deux exemples d'où je voudrais tester une méthode privée:

  1. Routines de décryptage - Je ne voudrais pas vouloir les rendre visibles à quiconque de voir juste pour le souci de tester, sinon n'importe qui peut Utilisez-les pour déchiffrer. Mais ils sont intrinsèque au code, compliqué, et doit toujours fonctionner (l'exception évidente est la réflexion qui peut être utilisée pour voir des méthodes même privées dans la plupart des cas, quand SecurityManager n'est pas configuré pour empêcher cela).
  2. Créer un SDK pour la communauté consommation. Ici le public prend un sens totalement différent, puisque cette est un code que le monde entier peut voir (pas seulement interne à mon application). je mets code dans des méthodes privées si je ne le fais pas veulent que les utilisateurs du SDK le voient - je ne vois pas cela comme une odeur de code, simplement comme fonctionne la programmation du SDK. Mais de Bien sûr, je dois encore tester mon méthodes privées, et ils sont là la fonctionnalité de mon SDK en fait vies.

Je comprends l'idée de tester uniquement le "contrat". Mais je ne vois pas que l'on peut recommander de ne pas tester le code - votre kilométrage peut varier.

Donc, mon compromis consiste à compliquer les JUnits avec la réflexion, plutôt que de compromettre ma sécurité et SDK.


56