web-dev-qa-db-fra.com

annotation pour rendre une méthode privée publique uniquement pour les classes de test

Qui a une solution pour ce besoin commun.

J'ai un cours dans mon application.

certaines méthodes sont publiques, car elles font partie de l'api, et d'autres sont privées, car elles sont destinées à un usage interne pour rendre le flux interne plus lisible.

maintenant, disons que je veux écrire un test unitaire, ou plutôt un test d'intégration, qui sera situé dans un paquet différent, qui sera autorisé à appeler cette méthode, MAIS, je veux que l'appel normal à cette méthode ne soit pas autorisé si vous essayez de l'appeler à partir de classes de l'application elle-même

alors, je pensais à quelque chose comme ça

public class MyClass {

   public void somePublicMethod() {
    ....
   }

   @PublicForTests
   private void somePrivateMethod() {
    ....
   }
}

L'annotation ci-dessus marquera la méthode privée comme "public pour les tests", ce qui signifie que la compilation et l'exécution seront autorisées pour toute classe soumise au paquet test ..., tandis que la compilation et/ou l'exécution échouera pour toute classe qui est pas sous le paquet de test.

des pensées? Y a-t-il une annotation comme celle-ci? Y a-t-il une meilleure manière de faire cela?

il semble que plus vous écrivez de tests unitaires, plus vous êtes forcé de casser votre encapsulation ...

80
Kumetix

La méthode habituelle consiste à rendre la méthode privée protégée ou package-private et à placer le test unitaire pour cette méthode dans le même package que la classe sous test. La goyave a un @VisibleForTesting annotation , mais c'est uniquement à des fins de documentation.

118
JB Nizet

Si votre couverture de test est bonne sur toutes les méthodes publiques de la classe testée, les méthodes privées appelées par la méthode publique seront automatiquement testées car vous pourrez faire valoir tous les cas possibles.

Le JUnit Doc dit:

Tester des méthodes privées peut indiquer que ces méthodes doivent être déplacées vers une autre classe afin de promouvoir la réutilisabilité. Mais si vous devez ... Si vous utilisez JDK version 1.3 ou ultérieure, vous pouvez utiliser la réflexion pour contourner le mécanisme de contrôle d'accès à l'aide de PrivilegedAccessor. Pour plus de détails sur son utilisation, lisez cet article.

21
Cygnusx1

Envisagez d'utiliser des interfaces pour exposer les méthodes de l'API, en utilisant des usines ou des ID pour publier les objets afin que les consommateurs ne les connaissent que par l'interface. L'interface décrit l'API publiée. De cette façon, vous pouvez rendre public ce que vous voulez sur les objets d'implémentation et les consommateurs ne voient que les méthodes exposées via l'interface.

10
Nathan Hughes

dp4j a ce dont vous avez besoin. Tout ce que vous avez à faire est d’ajouter dp4j à votre chemin de classe et chaque fois qu'une méthode annotée avec @Test (annotation de JUnit) appelle une méthode privée, cela fonctionnera (dp4j injectera la réflexion requise au moment de la compilation). Vous pouvez également utiliser l'annotation @TestPrivates de dp4j pour être plus explicite.

Si vous souhaitez également annoter vos méthodes privées, vous pouvez utiliser l'annotation @VisibleForTesting de Google.

5
simpatico

Ou vous pouvez extraire cette méthode dans un objet stratégie. Dans ce cas, vous pouvez facilement tester la classe extraite et ne pas rendre la méthode publique ou une méthode magique avec réflexion/bytecode.

2
Stan Kurilin

Un article sur Testing Private Methods expose certaines approches pour tester le code privé. L'utilisation de la réflexion impose un fardeau supplémentaire au programmeur, qui doit se rappeler que si la refactorisation est effectuée, les chaînes ne sont pas automatiquement modifiées, mais je pense que c'est l'approche la plus propre.

2
Atreys

Vous ne pouvez pas faire cela, depuis lors, comment pourriez-vous même compiler vos tests? Le compilateur ne prendra pas l'annotation en compte.

Il existe deux approches générales à cette

La première consiste à utiliser la réflexion pour accéder aux méthodes de toute façon

La seconde consiste à utiliser package-private au lieu de private, puis à placer vos tests dans le même package (mais dans un module différent). Ils seront essentiellement privés à d'autres codes, mais vos tests pourront toujours y accéder.

Bien sûr, si vous testez les boîtes noires, vous ne devriez de toute façon pas accéder aux membres privés.

1
Joeri Hendrickx

Ok, donc ici nous avons deux choses qui sont mélangées. La première chose à faire, c’est que lorsque vous devez marquer quelque chose à utiliser uniquement à des fins de test, ce que je partage avec @JB Nizet, l’utilisation de l’annotation goyave serait une bonne chose.

Une autre chose est de tester des méthodes privées. Pourquoi devriez-vous tester des méthodes privées de l'extérieur? Je veux dire .. Vous devriez être capable de tester l'objet par ses méthodes publiques, et à la fin que son comportement. Au moins, nous essayons d’enseigner aux développeurs débutants et essayons toujours de tester les méthodes privées (en tant que bonne pratique).

1
facundofarias

Nous avons récemment publié une bibliothèque qui aide beaucoup à accéder aux champs privés, aux méthodes et aux classes internes par réflexion: BoundBox

Pour un cours comme

public class Outer {
    private static class Inner {
        private int foo() {return 2;}
    }
}

Il fournit une syntaxe comme celle-ci:

Outer outer = new Outer();
Object inner = BoundBoxOfOuter.boundBox_new_Inner();
new BoundBoxOfOuter.BoundBoxOfInner(inner).foo();

La seule chose à faire pour créer la classe BoundBox est d'écrire @BoundBox(boundClass=Outer.class) et la classe BoundBoxOfOuter sera générée instantanément.

1
Snicolas

Je ne suis au courant d'aucune annotation de ce type. Toutefois, les éléments suivants peuvent être utiles: méthodes privées de test unitaire
ou les suivants: JMockit

1
Woot4Moo

Je viens de mettre le test dans la classe elle-même en en faisant une classe intérieure: http://www.ninthavenue.com.au/how-to-unit-test-private-methods

0
Roger Keays

Autant que je sache, il n'y a pas d'annotation comme celle-ci. Le meilleur moyen est d’utiliser la réflexion comme certains l’ont suggéré. Regardez ce post:
Comment tester une classe contenant des méthodes privées, des champs ou des classes internes?

Vous devez uniquement veiller à tester le résultat d'exception de la méthode. Par exemple, si vous attendez une exception IllegalArgumentException, vous obtiendrez plutôt la valeur "null" (Classe: Java.lang.reflect.InvocationTargetException).
Un de mes collègues a proposé d'utiliser le cadre de Powermock pour ces situations, mais je ne l'ai pas encore testé, donc je ne sais pas exactement ce qu'il peut faire. Bien que j’ai utilisé le framework Mockito sur lequel il est basé, c’est aussi un bon framework (mais je pense que cela ne résout pas le problème des exceptions de méthode privée).

C'est une bonne idée d'avoir l'annotation @PublicForTests.

À votre santé!

0
despot