Auparavant dans Ce que vous devez savoir lors de l'écriture de Java, ** les méthodes privées peuvent être appelées par réflexion, les modificateurs d'accès ne sont donc utilisés que pour les tests. J'ai écrit que vous ne devriez pas le supprimer **. Alors, voici un exemple.
S'il s'agit d'un champ au lieu d'une méthode, écrivez-le comme ceci. → Référez / définissez les variables privées en réflexion
2018/12/26 Ajouté "Appeler le constructeur privé"
Nous sommes conscients qu'il existe une opinion selon laquelle "il devrait être appelé de la méthode publique pour tester la méthode privée de manière cohérente". Cependant, selon le projet, il existe de nombreux cas qui incluent un test basé sur une méthode = méthode privée. C'est une regle. Tout le monde écrit le code de test en conséquence. Même si vous le cassez, il vous sera seulement demandé de le réécrire. En logique métier, il peut y avoir une méthode publique dans une classe. Dans un tel cas, le test est difficile. Il est plus facile d'écrire un test pour une méthode publique après avoir garanti le traitement pour chaque méthode privée avec un test. C'est pourquoi les avantages et les inconvénients des tests par méthode privée sont hors de portée.
L'exemple de code omet Javadoc et en quelque sorte. J'ai confirmé l'opération pour qu'elle fonctionne avec le copier-coller, mais ce n'est qu'un exemple de code et de référence.
Sample.java
public class Sample {
private String strValue = null;
public Sample(String value) {
this.strValue = (value == null) ? "" : value;
}
/** 5.Appeler un constructeur privé*/
private Sample() {
}
/** 1.Appel d'une méthode non statique*/
private boolean equals(String value) {
return this.strValue.equals(value);
}
/** 2.Appel d'une méthode statique*/
private static boolean isEmpty(String value) {
return (value == null || "".equals(value)) ? true : false;
}
/** 3.Appel sans valeur de retour ni argument*/
private static void dispMessage() {
System.out.println("Hello world!");
}
/** 4.Vérifier les exceptions*/
private void setValue(String value) {
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException("argument is empty.");
}
this.strValue = value;
}
}
doPrivateMethod est la méthode pour appeler la méthode privée testée. Dans les types, les types des arguments de la méthode privée sont stockés dans un tableau dans l'ordre à partir du premier argument et passés. args transmet également les arguments eux-mêmes. Étant donné que le nom de la méthode à tester, le type et le nombre d'arguments sont spécifiés, le test échouera si la zone est modifiée par refactorisation ou autre. (InvocationTargetException se produit)
SampleTest.java
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import org.junit.Test;
public class SampleTest {
@Test
public void test_equals() throws Exception {
Sample testee = new Sample("test");
assertTrue((boolean) this.doPrivateMethod(
testee, "equals", new Class[]{String.class}, new Object[]{"test"}));
}
/**
*Appel de méthode non statique.
*
* @param obj Objet testé
* @nom du paramètre Nom de la méthode testée
* @types de param Types d'argument de la méthode testée
* @param args Arguments de la méthode testée
* @return Valeur de retour de la méthode non statique
*/
private Object doPrivateMethod(
Object obj, String name, Class[] types, Object[] args) throws Exception {
//Obtenir des informations sur la méthode testée
Method method = obj.getClass().getDeclaredMethod(name, types);
//Supprimer les restrictions d'accès à la méthode testée
method.setAccessible(true);
//Appel de méthode testée
return method.invoke(obj, args);
}
}
doStaticPrivateMethod est la méthode pour appeler la méthode privée sous test. Ceux qui sont vulnérables au refactoring sont les mêmes que 1. Puisqu'il s'agit d'un appel à une méthode statique, aucun objet n'est passé en argument.
SampleTest.java
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import org.junit.Test;
public class SampleTest {
@Test
public void test_isEmpty() throws Exception {
assertTrue((boolean) this.doStaticPrivateMethod(
"isEmpty", new Class[]{String.class}, new Object[]{null}));
}
/**
*appel de méthode statique.
*
* @nom du paramètre Nom de la méthode testée
* @types de param Types d'argument de la méthode testée
* @param args Arguments de la méthode testée
* @retourne la valeur de retour de la méthode statique
*/
private Object doStaticPrivateMethod(
String name, Class[] types, Object[] args) throws Exception {
//Obtenir des informations sur la méthode testée
Method method = Sample.class.getDeclaredMethod(name, types);
//Supprimer les restrictions d'accès à la méthode testée
method.setAccessible(true);
//Appel de méthode testée
return method.invoke(null, args);
}
}
assertTrue((boolean) this.doStaticPrivateMethod("isEmpty", new Class[]{String.class}, new Object[]{null}));
Si vous voulez passer null dans une méthode avec des arguments, placez-le dans un tableau. Un tableau est requis même avec un argument. Si vous le passez tel quel, il échouera.
Si la méthode testée est nulle, il n'y a pas de valeur de retour. (Null même si vous essayez de le ramasser) Passez null lors de l'appel d'une méthode sans argument. Contrairement à 2., il n'est pas nécessaire que ce soit un tableau.
SampleTest.java
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import org.junit.Test;
public class SampleTest {
@Test
public void test_dispMessage() throws Exception {
this.doStaticPrivateMethod("dispMessage", null, null);
}
}
** Ajouté à partir des commentaires **
this.doStaticPrivateMethod("dispMessage", null, null);
Il n'est pas affirmé car il s'agit d'un exemple de méthode d'appel. Même lors du test d'une méthode d'annulation, il est essentiel de vérifier le résultat du traitement. Par exemple, si vous traitez une base de données ou un fichier, confirmez le résultat. Dans le cas de la classe Sample, vérifiez si la chaîne de caractères sortie vers la console est correcte. Par exemple, comme ça.
//Redirection des résultats de sortie standard
ByteArrayOutputStream out = new ByteArrayOutputStream();
System.setOut(new PrintStream(out));
//Appel testé
this.doStaticPrivateMethod("dispMessage", null, null);
//Affirmer
assertEquals("Hello world!" + System.lineSeparator(), out.toString());
Si vous souhaitez exécuter l'exemple, importez ByteArrayOutputStream et PrintStream.
Toutes les erreurs d'appel sont encapsulées et levées avec ** InvocationTargetException **. Par conséquent, la vérification des exceptions levées dans la cible de test est effectuée en extrayant le contenu encapsulé par InvocationTargetException. De plus, dans le cas d'un test qui confirme qu'une exception est levée, si l'exception n'est pas levée, ou si une exception autre que l'exception prévue se produit, le test échouera sur JUnit, donc ** échouera (explicitement ** échouera ( );**appel.
SampleTest.java
import static org.junit.Assert.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.junit.Test;
public class SampleTest {
@Test
public void test_setValue() throws Exception {
try {
Sample testee = new Sample("test");
this.doPrivateMethod(
testee, "setValue", new Class[]{String.class}, new Object[]{""});
//Test échoué
fail();
} catch (InvocationTargetException e) {
//Vérification du type d'exception
assertTrue(e.getCause() instanceof IllegalArgumentException);
//Vérification des messages d'exception
assertEquals("argument is empty.", e.getCause().getMessage());
} catch (Exception e) {
//Test échoué
fail(e.getMessage());
}
}
}
N'est-ce pas écrire un constructeur privé sans arguments pour l'empêcher d'être appelé de l'extérieur dans une classe statique? Telle est la méthode de test. Il est utilisé dans les projets où «100% de couverture» est une condition. Le commentaire dit «Écrivez le nom de la classe avec un nom complet», mais comme l'exemple de classe cette fois n'est pas empaqueté, seul le nom de la classe est décrit. Normalement, je pense qu'il existe un package, donc il ne fonctionnera pas à moins que ce soit un nom complet.
SampleTest.java
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.*;
import java.lang.reflect.Constructor;
import org.junit.Test;
public class SampleTest {
@Test
public void test_private_constructor() {
try {
//Décrivez le nom de la classe comme un nom complet
Class<?> clazz = Class.forName("Sample");
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
constructors[1].setAccessible(true);
Object obj = constructors[1].newInstance();
assertNotNull(obj);
assertThat(obj, instanceOf(clazz));
} catch (Exception e) {
fail(e.getMessage());
}
}
}
constructors[1].setAccessible(true);
Ici, décrivez l'ordre décrit dans la classe Sample avec 0 origine. Dans ce cas, le constructeur privé que vous souhaitez tester est le deuxième des constructeurs de classe Sample, il sera donc "1". Si vous n'avez qu'un constructeur à tester, "0" convient.
Bonne vie à Java! Si quelque chose arrive, je l'écrirai dans un post-scriptum ou un autre article.
Recommended Posts