Oui, C’est la question à un million de dollars. Comment tester des méthodes privées à l’unité?
Un développeur doit-il tester les méthodes privées dans sa base de code? ou les laisser sur la confiance des méthodes publiques est un moyen. Chaque développeur a sa propre opinion sur le fait de savoir si nous devrions réellement les tester ou non. Donc, en un mot, la question s’est réduite à la suivante: « Existe-t-il une bonne approche que nous pouvons essayer pour ce travail? »
Voici donc toutes les options possibles à la disposition d’un développeur pour tester les méthodes privées de ses applications basées sur Java/kotlin en 2019:
- Ne testez pas les méthodes privées 😜 (Pas de racines, pas de raisins acides)
- Donnez aux méthodes un accès public ( (Non, je ne le ferai pas, c’est contre les pratiques de codage. Je suis un bon développeur, je suis les meilleures pratiques)
- Utilisez une classe de test imbriquée 😒 (Ce n’est pas bon de mélanger du code de production avec du code de test. Dois-je mentionner à nouveau que je suis un bon développeur et que je ne suis que les meilleures pratiques)
- Utilisez la réflexion Java 😃 (Oui, cela semble intéressant, j’y suis)
Malgré la croyance commune, il est en fait possible d’accéder à des champs privés et à des méthodes d’autres classes via la réflexion Java. Ce n’est même pas si difficile. Cela peut être très pratique lors des tests unitaires.
Remarque: Cela ne fonctionne que lors de l’exécution du code en tant qu’application Java autonome, comme vous le faites avec les tests unitaires et les applications régulières. Si vous essayez de le faire dans une applet Java, vous devrez jouer avec le SecurityManager. Mais, comme ce n’est pas quelque chose que vous devez faire très souvent, il est exclu de ce texte jusqu’à présent.
La prise en charge de la réflexion des paramètres de méthode a été ajoutée dans Java 8. En termes simples, il prend en charge l’obtention des noms des paramètres à l’exécution.
Pour accéder à un champ privé, vous devrez appeler la méthode Class.getDeclaredField(String name)
ou Class.getDeclaredFields()
. Les méthodes Class.getField(String name)
et Class.getFields()
ne renvoient que des champs publics, elles ne fonctionneront donc pas. Voici un exemple simple d’une classe avec un champ privé, et ci-dessous le code pour accéder à ce champ via la réflexion Java:
public class PrivateObject {private String privateString = null;public PrivateObject(String privateString) {
this.privateString = privateString;
}
}PrivateObject privateObject = new PrivateObject("The Private Value");Field privateStringField = PrivateObject.class.
getDeclaredField("privateString");privateStringField.setAccessible(true);String fieldValue = (String) privateStringField.get(privateObject);
System.out.println("fieldValue = " + fieldValue);
Cet exemple de code imprimera le texte "fieldValue = The Private Value”
, qui est la valeur du champ privé privateString
du PrivateObject
l’instance créée au début de l’exemple de code.
Notez l’utilisation de la méthode PrivateObject.class.getDeclaredField("privateString")
. C’est cet appel de méthode qui renvoie le champ privé. Cette méthode renvoie uniquement les champs déclarés dans cette classe particulière, pas les champs déclarés dans les superclasses.
Notez également la ligne en gras. En appelant Field.setAcessible(true)
vous désactivez les contrôles d’accès pour cette instance particulière Field
, uniquement pour la réflexion. Vous pouvez maintenant y accéder même s’il s’agit d’une portée privée, protégée ou de package, même si l’appelant ne fait pas partie de ces étendues. Vous ne pouvez toujours pas accéder au champ en utilisant le code normal. Le compilateur ne le permettra pas.
Accès aux méthodes privées
Pour accéder à une méthode privée, vous devrez appeler la méthode Class.getDeclaredMethod(String name, Class parameterTypes)
ou Class.getDeclaredMethods()
. Les méthodes Class.getMethod(String name, Class parameterTypes)
et Class.getMethods()
ne renvoient que des méthodes publiques, elles ne fonctionneront donc pas.
Voici un exemple simple d’une classe avec une méthode privée, et ci-dessous le code pour accéder à cette méthode via la réflexion Java:
public class PrivateObject {private String privateString = null;public PrivateObject(String privateString) {
this.privateString = privateString;
}private String getPrivateString(){
return this.privateString;
}
}PrivateObject privateObject = new PrivateObject("The Private Value");Method privateStringMethod = PrivateObject.class.
getDeclaredMethod("getPrivateString", null);privateStringMethod.setAccessible(true);String returnValue = (String)
privateStringMethod.invoke(privateObject, null);System.out.println("returnValue = " + returnValue);
Cet exemple de code imprimera le texte "returnValue = The Private Value”
, qui est la valeur renvoyée par la méthode getPrivateString()
lorsqu’elle est invoquée sur le PrivateObject
l’instance créée au début du code échantillon.
Notez l’utilisation de la méthode PrivateObject.class.getDeclaredMethod("privateString")
. C’est cet appel de méthode qui renvoie la méthode privée. Cette méthode renvoie uniquement les méthodes déclarées dans cette classe particulière, pas les méthodes déclarées dans les superclasses.
Notez également la ligne en gras. En appelant Method.setAcessible(true)
vous désactivez les contrôles d’accès pour cette instance particulière Method
, uniquement pour la réflexion. Vous pouvez maintenant y accéder même s’il s’agit d’une portée privée, protégée ou de package, même si l’appelant ne fait pas partie de ces étendues. Vous ne pouvez toujours pas accéder à la méthode en utilisant le code normal. Le compilateur ne le permettra pas.
Essayons ces connaissances à un code au niveau de la production.
Voici la classe contenant quelques méthodes privées que nous voulons tester.