Comment utiliser JUnit pour tester une classe qui contient des méthodes, des champs ou des classes imbriquées privées?
Il semble inapproprié de changer le modificateur d'accès d'une méthode juste pour pouvoir exécuter un test.
Comment utiliser JUnit pour tester une classe qui contient des méthodes, des champs ou des classes imbriquées privées?
Il semble inapproprié de changer le modificateur d'accès d'une méthode juste pour pouvoir exécuter un test.
Si vous avez quelque chose d'hérité d'une application Java, et que vous n'êtes pas autorisé à changer la visibilité de vos méthodes, la meilleure façon de tester les méthodes privées est d'utiliser la réflexion.
En interne, nous utilisons des aides pour obtenir/définir des variables private
et private static
ainsi que pour invoquer des méthodes private
et private static
. Les motifs suivants vous permettront de faire à peu près tout ce qui concerne les méthodes privées et les champs. Bien sûr, vous ne pouvez pas changer les variables private static final
via 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);
Notes:
TargetClass.getDeclaredMethod(methodName, argClasses)
vous permet d'examiner les méthodesprivate
. La même chose s'applique pourgetDeclaredField
.setAccessible(true)
est requis pour jouer avec les éléments privés.
Utile si vous ne connaissez pas éventuellement l'API, mais si vous devez tester les méthodes privées de cette manière, il y a quelque chose de problématique avec votre design. Comme un autre intervenant l'a dit, les tests unitaires doivent tester le contrat de la classe : si le contrat est trop large et instancie trop de parties du système, alors le design devrait être revu.
La meilleure façon de tester une méthode privée est via une autre méthode publique. Si cela ne peut pas être fait, alors l'une des conditions suivantes est vraie:
De plus, nous n'atteignons jamais un taux de couverture de code de 100 % de toute façon, alors pourquoi ne pas consacrer votre temps à faire des tests de qualité sur les méthodes que les clients utiliseront réellement directement.
@grinch Tout à fait. La seule chose que vous gagneriez en testant les méthodes privées est des informations de débogage, et c'est ce que les débogueurs sont là pour cela. Si vos tests du contrat de la classe ont une couverture complète, alors vous avez toutes les informations dont vous avez besoin. Les méthodes privées sont un détail d'implémentation. Si vous les testez, vous devrez changer vos tests à chaque fois que votre implémentation change, même si le contrat ne change pas. Sur tout le cycle de vie du logiciel, cela coûtera probablement beaucoup plus que l'avantage qu'il apporte.
Je suis impressionné par la fréquence avec laquelle l'affirmation "ne doit pas être privé" est répétée dans les réponses ici, comme si "le rendre public pour que vous puissiez le tester" ne pouvait pas facilement conduire à un code mal écrit qui invite les autres à abuser de certaines parties d'une classe. Exposer des parties sensibles en interne juste pour tester plus facilement les différents chemins du code n'est pas toujours sensé, alors ne suivez pas aveuglément cet appareil ici !
Quand j'ai des méthodes privées dans une classe qui sont suffisamment compliquées pour que j'ai besoin de tester les méthodes privées directement, c'est une odeur de code : ma classe est trop compliquée.
Ma démarche habituelle pour résoudre de tels problèmes est d'extraire une nouvelle classe qui contient les parties intéressantes. Souvent, cette méthode et les champs avec lesquels elle interagit, et peut-être une autre méthode ou deux peuvent être extraites dans une nouvelle classe.
La nouvelle classe expose ces méthodes comme \'public\', donc elles sont accessibles pour les tests unitaires. Les nouvelles et anciennes classes sont maintenant toutes deux plus simples que la classe originale, ce qui est génial pour moi (j'ai besoin de garder les choses simples, sinon je me perds!).
Remarquez que je ne suggère pas aux gens de créer 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.
La question était de savoir comment tester les méthodes privées. Vous dites que vous créeriez une nouvelle classe pour cela (et ajouterez beaucoup plus de complexité) et ensuite suggérez de ne pas créer de nouvelle classe. Comment donc tester les méthodes privées?
Je pense que si vous avez une méthode, il n'est pas nécessaire de créer une autre classe juste pour pouvoir tester cette méthode. Je ne pense pas que la conception de la classe soit remise en question ici.. Donc je suppose que l'auteur a tout fait pour avoir une conception appropriée avant, donc en introduisant une autre classe pour une méthode, vous ne faites qu'augmenter la complexité. Bien sûr, lorsque vous avez un programme assez complexe, il n'y aura pas de bugs évidents..
@Dainius: Je ne suggère pas de créer une nouvelle classe unique uniquement pour que vous puissiez tester cette méthode. Je suggère que l'écriture de tests peut vous aider à améliorer votre conception : les bonnes conceptions sont faciles à tester.
J'ai utilisé la réflexion pour faire cela pour Java dans le passé, et à mon avis c'était une grosse erreur.
Strictement parlant, vous ne devriez pas écrire des tests unitaires qui testent directement les méthodes privées. Ce que vous devriez tester est le contrat public que la classe a avec d'autres objets; vous ne devriez jamais tester directement les parties internes d'un objet. Si un autre développeur veut apporter une petite modification interne à la classe, qui n'affecte pas le contrat public de la classe, il doit alors modifier votre test basé sur la réflexion pour s'assurer qu'il fonctionne. Si vous faites cela 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 une source de frustration pour l'équipe de développement.
Ce que je recommande plutôt, c'est d'utiliser un outil de couverture de code, tel que Cobertura, pour vous assurer que les tests unitaires que vous écrivez offrent une bonne couverture du code dans les méthodes privées. De cette manière, vous testez indirectement ce que font les méthodes privées, et maintenez un niveau plus élevé d'agilité.
+1 à cela. À mon avis, c'est la meilleure réponse à la question. En testant les méthodes privées, vous testez l'implémentation. Cela va à l'encontre de l'objectif des tests unitaires, qui consiste à tester les entrées/sorties du contrat d'une classe. Un test ne devrait seulement connaître suffisamment l'implémentation pour imiter les méthodes qu'il appelle sur ses dépendances. Rien de plus. Si vous ne pouvez pas modifier votre implémentation sans avoir à modifier un test - il est probable que votre stratégie de test est mauvaise.
@Colin M Ce n'est pas vraiment ce qu'il demande ;) Laisse-le décider, tu ne connais pas le projet.
Pas vraiment vrai. Il pourrait falloir beaucoup d'efforts pour tester une petite partie de la méthode privée à travers la méthode publique l'utilisant. La méthode publique pourrait nécessiter une configuration importante avant d'atteindre la ligne qui appelle votre méthode privée.
À partir de cet article: Testing Private Methods with JUnit and SuiteRunner (Bill Venners), vous avez essentiellement 4 options:
- Ne testez pas les méthodes privées.
- Donnez accès aux méthodes du package.
- Utilisez une classe de test imbriquée.
- Utilisez la réflexion.
@JimmyT., Cela dépend de pour qui est le "code de production". J'appellerais code produit pour les applications situées dans un VPN dont les utilisateurs cibles sont des administrateurs système pour être un code de production.
5ème option, comme mentionné ci-dessus, consiste à tester la méthode publique qui appelle la méthode privée? Correct?
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
277 votes
La meilleure façon de tester une méthode privée n'est pas de la tester directement
27 votes
Vérifiez l'article Testing Private Methods with JUnit and SuiteRunner.