Auparavant, j'ai écrit un article Test des méthodes privées dans JUnit. En bref, vous pouvez également tester ** des méthodes privées directement depuis JUnit! Ne soyez donc pas stupide de rendre public ou non un modificateur d'accès pour JUnit! C'est à cause de l'affirmation que **, mais c'est comme un dérivé de celui-ci.
Ce n'est pas une décoration, le modificateur d'accès est Hahan. Pensez à la signification et attachez-la.
C'est le putain de code que l'intention du modificateur d'accès semble être uniquement à des fins de test, et c'est juste ** nuisible **. Le code et les documents de conception de tels projets devront être jugés peu fiables et tout devra être suspecté, ce qui augmentera l'effort réel par rapport à l'estimation approximative. (Histoire d'expérience)
Si vous utilisez la bibliothèque fictive, vous pouvez écrire plus facilement sans utiliser de réflexion (comme la Whitebox de Mockito), mais ** Si vous frappez un projet qui n'est pas autorisé à introduire la bibliothèque fictive, il y a des gens qui suppriment négligemment le modificateur d'accès ** , J'ai écrit cet article. Arrêtez! s'il te plaît, arrête! Arrêtez d'écrire le mauvais code pour le test! vraiment! !!
Définit / référence la variable privée de la classe à tester à partir d'une autre classe JUnit. 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.
Le constructeur est omis. Fondamentalement, il a juste une variable privée et un getter qui référence la variable privée.
package test.variable;
import java.util.Objects;
public class Sample {
/ ** 1. variable d'instance privée * /
private String strValue = null;
/ ** 2. variable de classe privée * /
private static String strValueStatic = null;
private InnerDynamic innerDynamic = null;
private static InnerStatic innerStatic = new InnerStatic();
public String getStrValue() {
return this.strValue;
}
public static String getStrValueStatic() {
return strValueStatic;
}
public String getDynamicInnerPrivate() {
if (Objects.isNull(this.innerDynamic)) {
this.innerDynamic = new InnerDynamic();
}
return this.innerDynamic.getIStrValue();
}
public static String getStaticInnerPrivate() {
return innerStatic.getIStrValue();
}
private class InnerDynamic {
/ ** 3. Variable d'instance de classe privée dynamique * /
private String iStrValue = null;
public String getIStrValue() {
return this.iStrValue;
}
}
private static class InnerStatic {
/ ** 4. Variable d'instance de classe privée statique * /
private String iStrValue = null;
public String getIStrValue() {
return this.iStrValue;
}
}
}
Le type qui nécessite une instance car il n'est pas statique. Vous permet de parcourir et de définir des variables privées pour une instance particulière.
package test.variable;
import static org.junit.Assert.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import org.junit.Test;
public class SampleTest {
/ ** 1. variable d'instance privée * /
@Test
public void test_private_field() throws Exception {
String testValue = "test";
Sample testee = new Sample();
// Vérifier la valeur initiale
assertNull(testee.getStrValue());
// Récupère le champ de la variable privée
Field field = testee.getClass().getDeclaredField("strValue");
// Supprimer les restrictions d'accès sur les variables privées
field.setAccessible(true);
// Définit une valeur pour une variable privée
field.set(testee, testValue);
// Vérifier les variables privées
String value = String.valueOf(field.get(testee));
assertEquals(testValue, value);
assertEquals(value, testee.getStrValue());
}
}
Dans le cas de statique, le contenu d'une instance spécifique n'est pas modifié, de sorte que l'objet de classe n'est pas obtenu à partir de l'instance, ou le premier argument est défini sur null lors de la définition de la valeur.
package test.variable;
import static org.junit.Assert.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import org.junit.Test;
public class SampleTest {
/ ** 2. variable de classe privée * /
@Test
public void test_private_static_field() throws Exception {
String testValue = "test";
// Vérifier la valeur initiale
assertNull(Sample.getStrValueStatic());
// Récupère le champ de la variable privée
Field field = Sample.class.getDeclaredField("strValueStatic");
// Supprimer les restrictions d'accès sur les variables privées
field.setAccessible(true);
// Définit une valeur pour une variable privée
field.set(null, testValue);
// Vérifier les variables privées
String value = String.valueOf(field.get(null));
assertEquals(testValue, value);
assertEquals(value, Sample.getStrValueStatic());
}
}
Dans le cas de la classe interne, elle est invisible pour la classe externe, nous obtenons donc le constructeur via le chargeur de classe.
Pour l'obtenir, spécifiez class $ inner class
en dehors du nom complet.
Après avoir obtenu l'objet de classe interne, récupérez le champ comme ci-dessus et supprimez les restrictions d'accès sur le champ.
package test.variable;
import static org.junit.Assert.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import org.junit.Test;
public class SampleTest {
/ ** 3. Variable d'instance de classe privée dynamique * /
@Test
public void test_dynamic_inner_class_private_field() throws Exception {
String testValue = "test";
Sample testee = new Sample();
// Vérifier la valeur initiale
assertNull(testee.getDynamicInnerPrivate());
// Récupère l'objet de classe interne
Class innerClazz = Class.forName("test.variable.Sample$InnerDynamic");
Constructor constructor = innerClazz.getDeclaredConstructor(new Class[]{Sample.class});
constructor.setAccessible(true);
Object inner = constructor.newInstance(testee);
// Récupère le champ de la variable privée de la classe interne
Field field = inner.getClass().getDeclaredField("iStrValue");
field.setAccessible(true);
field.set(inner, testValue);
// Récupère le champ qui contient la classe interne de la classe externe
Field outerFld = testee.getClass().getDeclaredField("innerDynamic");
outerFld.setAccessible(true);
outerFld.set(testee, inner);
// Vérifier les variables privées
String value = String.valueOf(field.get(inner));
assertEquals(testValue, value);
assertEquals(value, testee.getDynamicInnerPrivate());
}
Si le constructeur de classe interne a un argument, le premier argument sera la classe ou l'objet externe, donc le deuxième argument et les suivants seront les arguments du constructeur de classe interne.
// Récupère le constructeur
Constructor constructor =
innerClazz.getDeclaredConstructor(new Class[]{Sample.class, String.class});
// Récupère l'objet
Object inner = constructor.newInstance(testee, "constructor");
Comme pour la classe interne dynamique, récupérez d'abord le constructeur.
Pour l'obtenir, spécifiez class $ inner class
en dehors du nom complet.
La différence entre les classes internes statiques et dynamiques est que la classe externe est spécifiée dans le premier argument transmis au moment de l'acquisition.
package test.variable;
import static org.junit.Assert.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import org.junit.Test;
public class SampleTest {
/ ** 4. Variable d'instance de classe privée statique * /
@Test
public void test_static_inner_class_private_field() throws Exception {
String testValue = "test";
// Vérifier la valeur initiale
assertNull(Sample.getStaticInnerPrivate());
// Récupère l'objet de classe interne
Class innerClazz = Class.forName("test.variable.Sample$InnerStatic");
Constructor constructor = innerClazz.getDeclaredConstructor();
constructor.setAccessible(true);
Object inner = constructor.newInstance();
// Récupère le champ de la variable privée de la classe interne
Field field = inner.getClass().getDeclaredField("iStrValue");
field.setAccessible(true);
field.set(inner, testValue);
// Récupère le champ qui contient la classe interne de la classe externe
Field outerFld = Sample.class.getDeclaredField("innerStatic");
outerFld.setAccessible(true);
outerFld.set(null, inner);
// Vérifier les variables privées
String value = String.valueOf(field.get(inner));
assertEquals(testValue, value);
assertEquals(value, Sample.getStaticInnerPrivate());
}
}
L'exemple appelle un constructeur sans argument, mais dans le cas d'un constructeur comme ʻInnerStatic (String str) `, spécifiez le type et la valeur de l'argument au moment de l'acquisition.
// Récupère le constructeur
Constructor constructor = innerClazz.getDeclaredConstructor(new Class[]{String.class});
// Récupère l'objet
Object inner = constructor.newInstance("constructor");
Eh bien, parce que c'est un test, j'utilise la réflexion pour appeler des champs invisibles et des méthodes comme celle-ci, mais juste parce que je peux l'appeler, je pense que c'est une bonne idée d'utiliser la réflexion sur la personne testée. Je ne pense pas qu'il soit courant d'utiliser la réflexion dans la source du programme lui-même, donc si vous l'utilisez, il peut être préférable de l'examiner à partir de la conception. (Sauf si vous créez le framework lui-même) Si vous n'êtes pas sûr, parlez à quelqu'un qui vous connaît peut-être. Surtout dans les environnements où les révisions de code ne sont pas effectuées correctement.
prime Non, je suis en train de changer d'emploi, mais je recherche un lieu de travail où je peux écrire mon propre code (même en donnant des conseils techniques aux nouveaux arrivants). Je suis le genre de personne qui ne convient pas à la direction, alors veuillez me contacter si vous avez un bon lieu de travail pour écrire du code.
Recommended Posts