[Java] Se référer et définir des variables privées avec réflexion

Se référer et définir des variables privées

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


Exemple de code et exemples

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.

Classe à tester

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;
		}
	}
}

1. Paramètre / référence de variable d'instance privée

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());
	}
}

2. Paramètre / référence de variable de classe privée

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());
	}
}

3. Définition / référence des variables d'instance de la classe privée dynamique

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 prend un argument

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");

4. Définition / référence des variables d'instance de la classe privée statique

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());
	}
}

Si le constructeur prend un argument

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");

finalement

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

[Java] Se référer et définir des variables privées avec réflexion
Essayez d'intégrer Ruby et Java avec Dapr
Comment accéder aux méthodes et champs Java Private
[Java] Types de variables et types
Comment appeler des fonctions en bloc avec la réflexion Java
Renommer la feuille Java Excel et définir les couleurs des onglets
Je veux faire des transitions d'écran avec kotlin et java!
Java pour jouer avec Function
Programmation Java (variables et données)
Comment définir des constantes Java
Connectez-vous à DB avec Java
Connectez-vous à MySQL 8 avec Java
Comment utiliser les variables Java
Comment définir des variables d'environnement lors de l'utilisation de Payjp avec Rails
Je veux faire une liste avec kotlin et java!
Je veux créer une fonction avec kotlin et java!
Comment définir et décrire des variables d'environnement à l'aide de Rails zsh
Exemple de code pour analyser la date et l'heure avec SimpleDateFormat de Java
Je veux implémenter diverses fonctions avec kotlin et java!
Java pour apprendre avec les ramen [Partie 1]
Utiliser java avec MSYS et Cygwin
Traçage distribué avec OpenCensus et Java
Mémo personnel: métaprogrammation avec réflexion Java
[Java] Points à noter avec Arrays.asList ()
Série Java Primer (variations et types)
[Introduction à Java] À propos des variables et des types (déclaration de variable, initialisation, type de données)
Je veux revenir à l'écran précédent avec kotlin et java!
Bases du développement Java ~ Comment écrire des programmes (variables et types) ~
Osez défier Kaggle avec Java (1)
Utilisez JDBC avec Java et Scala.
[Traitement × Java] Comment utiliser les variables
J'ai essayé d'interagir avec Java
Sortie PDF et TIFF avec Java 8
Parcourez Java et MySQL PATH avec des variables d'environnement [version Windows]
[Java] Tester des méthodes privées avec JUnit
Comment nommer des variables en Java
Java, des tableaux pour débuter avec les débutants
Crypter avec Java et décrypter avec C #
Comment tester une méthode privée et la simuler partiellement en Java
Je veux afficher des images avec REST Controller de Java et Spring!
Comment créer une application avec un mécanisme de plug-in [C # et Java]
Java8 / 9 Beginners: Streaming API addiction points et comment les gérer
Java pour les débutants, les variables et les types
Comment compiler Java avec VsCode & Ant
Surveillez les applications Java avec jolokia et hawtio
Lier le code Java et C ++ avec SWIG
Essayons WebSocket avec Java et javascript!
Introduction aux algorithmes avec java-Search (recherche prioritaire en profondeur)
Implémentation Java pour créer et résoudre des labyrinthes
[Java] Lecture et écriture de fichiers avec OpenCSV
[Java] Différences entre les variables d'instance et les variables de classe
[Java] Comment sortir et écrire des fichiers!
Comment configurer et utiliser kapt
[Java] Comment régler la date sur 00:00:00
Comment définir JAVA_HOME avec l'appassembler-maven-plugin de Maven
Forcer non immuable avec le constructeur privé Effective Java
Programmation Java (clause statique et "variables de classe")
[Introduction à Java] À propos des déclarations et des types de variables
Comment tester l'étendue privée avec JUnit