2938 votes

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

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.

277 votes

La meilleure façon de tester une méthode privée n'est pas de la tester directement

27 votes

1741voto

Cem Catikkas Points 4986

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:

  1. TargetClass.getDeclaredMethod(methodName, argClasses) vous permet d'examiner les méthodes private. La même chose s'applique pour getDeclaredField.
  2. setAccessible(true) est requis pour jouer avec les éléments privés.

377 votes

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.

714voto

Trumpi Points 4190

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:

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

8 votes

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.

47 votes

@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.

0 votes

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 !

349voto

Jay Bazuzi Points 20462

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.

28 votes

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?

4 votes

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..

29 votes

@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.

304voto

Jon Points 1381

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é.

79 votes

+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.

12 votes

@Colin M Ce n'est pas vraiment ce qu'il demande ;) Laisse-le décider, tu ne connais pas le projet.

3 votes

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.

220voto

Iker Jimenez Points 3351

À partir de cet article: Testing Private Methods with JUnit and SuiteRunner (Bill Venners), vous avez essentiellement 4 options:

  1. Ne testez pas les méthodes privées.
  2. Donnez accès aux méthodes du package.
  3. Utilisez une classe de test imbriquée.
  4. Utilisez la réflexion.

0 votes

@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.

0 votes

@Pacerier Que voulez-vous dire?

1 votes

5ème option, comme mentionné ci-dessus, consiste à tester la méthode publique qui appelle la méthode privée? Correct?

Prograide.com

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.

Powered by:

X