[Java] Verweisen Sie auf und setzen Sie private Variablen mit Reflektion

Verweisen Sie auf private Variablen und legen Sie diese fest

Zuvor schrieb ich einen Artikel Testen privater Methoden in JUnit. Kurz gesagt, Sie können ** private Methoden auch direkt von JUnit aus testen! Seien Sie also bitte nicht dumm, einen Zugriffsmodifikator für JUnit öffentlich zu machen oder gar nicht! Es ist wegen der Behauptung, dass **, aber es ist wie eine Ableitung davon.

Es ist keine Dekoration. Der Zugriffsmodifikator ist Hahan. Denken Sie über die Bedeutung nach und hängen Sie sie an.

Es ist der verdammte Code, den der Zugriffsmodifikator nur zum Testen zu verwenden scheint, und er ist nur ** schädlich **. Der Code und die Entwurfsunterlagen für solche Projekte müssen als unzuverlässig beurteilt und alle in Frage gestellt werden, was zu einem höheren tatsächlichen Aufwand als die grobe Schätzung führt. (Geschichte erleben)

Wenn Sie die Mock-Bibliothek verwenden, können Sie einfacher schreiben, ohne Reflection zu verwenden (z. B. Mockitos Whitebox). ** Wenn Sie jedoch auf ein Projekt stoßen, das die Einführung der Mock-Bibliothek nicht zulässt, gibt es Personen, die den Zugriffsmodifikator achtlos entfernen ** Ich habe diesen Artikel geschrieben. Halt! bitte hör auf! Hör auf, den falschen verdammten Code zum Testen zu schreiben! Ja wirklich! !!


Beispielcode und Beispiele

Setzen / referenzieren Sie die private Variable der Klasse, die von einer anderen JUnit-Klasse getestet werden soll. Der Beispielcode lässt Javadoc weg und irgendwie. Ich habe den Vorgang bestätigt, damit er mit Kopieren und Einfügen funktioniert, aber es ist nur ein Beispielcode und eine Referenz.

Zu testende Klasse

Der Konstruktor wird weggelassen. Grundsätzlich hat es nur eine private Variable und einen Getter, der auf die private Variable verweist.

package test.variable;

import java.util.Objects;

public class Sample {
	
 / ** 1. private Instanzvariable * /
	private String strValue = null;

 / ** 2. private Klassenvariable * /
	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. Dynamische Instanzvariable für private Klassen * /
		private String iStrValue = null;

		public String getIStrValue() {
			return this.iStrValue;
		}
	}

	private static class InnerStatic {
 / ** 4. Statische Instanzvariable der privaten Klasse * /
		private String iStrValue = null;

		public String getIStrValue() {
			return this.iStrValue;
		}
	}
}

1. Einstellung / Referenz der Variablen für private Instanzen

Der Typ, für den eine Instanz erforderlich ist, da sie nicht statisch ist. Ermöglicht das Durchsuchen und Festlegen privater Variablen für eine bestimmte Instanz.

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. private Instanzvariable * /
	@Test
	public void test_private_field() throws Exception {
		String testValue = "test";
		Sample testee = new Sample();
 // Überprüfen Sie den Anfangswert
		assertNull(testee.getStrValue());

 // Hole das Feld der privaten Variablen
		Field field = testee.getClass().getDeclaredField("strValue");
 // Zugriffsbeschränkungen für private Variablen entfernen
		field.setAccessible(true);
 // Setze einen Wert für eine private Variable
		field.set(testee, testValue);

 // Private Variablen prüfen
		String value = String.valueOf(field.get(testee));
		assertEquals(testValue, value);
		assertEquals(value, testee.getStrValue());
	}
}

2. Einstellung / Referenz der Variablen für private Klassen

Im Fall von statisch wird der Inhalt einer bestimmten Instanz nicht geändert, sodass das Klassenobjekt nicht von der Instanz abgerufen wird oder das erste Argument beim Festlegen des Werts auf null gesetzt wird.

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. private Klassenvariable * /
	@Test
	public void test_private_static_field() throws Exception {
		String testValue = "test";
 // Überprüfen Sie den Anfangswert
		assertNull(Sample.getStrValueStatic());

 // Hole das Feld der privaten Variablen
		Field field = Sample.class.getDeclaredField("strValueStatic");
 // Zugriffsbeschränkungen für private Variablen entfernen
		field.setAccessible(true);
 // Setze einen Wert für eine private Variable
		field.set(null, testValue);
		
 // Private Variablen prüfen
		String value = String.valueOf(field.get(null));
		assertEquals(testValue, value);
		assertEquals(value, Sample.getStrValueStatic());
	}
}

3. Festlegen / Referenzieren von Instanzvariablen einer dynamischen privaten Klasse

Im Fall der inneren Klasse ist sie für die äußere Klasse unsichtbar, sodass wir den Konstruktor über den Klassenlader erhalten. Geben Sie dazu "class $ inner class" außerhalb des vollständig qualifizierten Namens an. Nachdem Sie das Objekt der inneren Klasse abgerufen haben, rufen Sie das Feld wie oben beschrieben ab und entfernen Sie die Zugriffsbeschränkungen für das Feld.

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. Dynamische Instanzvariable für private Klassen * /
	@Test
	public void test_dynamic_inner_class_private_field() throws Exception {
		String testValue = "test";
		Sample testee = new Sample();
 // Überprüfen Sie den Anfangswert
		assertNull(testee.getDynamicInnerPrivate());

 // Hole das innere Klassenobjekt
		Class innerClazz = Class.forName("test.variable.Sample$InnerDynamic");
		Constructor constructor = innerClazz.getDeclaredConstructor(new Class[]{Sample.class});
		constructor.setAccessible(true);
		Object inner = constructor.newInstance(testee);
 // Hole das Feld der privaten Variablen der inneren Klasse
		Field field = inner.getClass().getDeclaredField("iStrValue");
		field.setAccessible(true);
		field.set(inner, testValue);
 // Hole das Feld, das die innere Klasse der äußeren Klasse enthält
		Field outerFld = testee.getClass().getDeclaredField("innerDynamic");
		outerFld.setAccessible(true);
		outerFld.set(testee, inner);
		
 // Private Variablen prüfen
		String value = String.valueOf(field.get(inner));
		assertEquals(testValue, value);
		assertEquals(value, testee.getDynamicInnerPrivate());
	}

Wenn der Konstruktor ein Argument akzeptiert

Wenn der Konstruktor der inneren Klasse ein Argument hat, ist das erste Argument die äußere Klasse oder das äußere Objekt, sodass das zweite und die nachfolgenden Argumente die Argumente des Konstruktors der inneren Klasse sind.

 // Den Konstruktor holen
Constructor constructor = 
		innerClazz.getDeclaredConstructor(new Class[]{Sample.class, String.class});

 // Holen Sie sich das Objekt
Object inner = constructor.newInstance(testee, "constructor");

4. Setzen / Referenzieren von Instanzvariablen der statischen privaten Klasse

Holen Sie sich wie bei der dynamischen inneren Klasse zuerst den Konstruktor. Geben Sie dazu "class $ inner class" außerhalb des vollständig qualifizierten Namens an. Der Unterschied zwischen der statischen und der dynamischen inneren Klasse besteht darin, dass die äußere Klasse im ersten Argument angegeben wird, das zum Zeitpunkt der Erfassung übergeben wurde.

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. Statische Instanzvariable der privaten Klasse * /
	@Test
	public void test_static_inner_class_private_field() throws Exception {
		String testValue = "test";
 // Überprüfen Sie den Anfangswert
		assertNull(Sample.getStaticInnerPrivate());

 // Hole das innere Klassenobjekt
		Class innerClazz = Class.forName("test.variable.Sample$InnerStatic");
		Constructor constructor = innerClazz.getDeclaredConstructor();
		constructor.setAccessible(true);
		Object inner = constructor.newInstance();
 // Hole das Feld der privaten Variablen der inneren Klasse
		Field field = inner.getClass().getDeclaredField("iStrValue");
		field.setAccessible(true);
		field.set(inner, testValue);
 // Hole das Feld, das die innere Klasse der äußeren Klasse enthält
		Field outerFld = Sample.class.getDeclaredField("innerStatic");
		outerFld.setAccessible(true);
		outerFld.set(null, inner);
		
 // Private Variablen prüfen
		String value = String.valueOf(field.get(inner));
		assertEquals(testValue, value);
		assertEquals(value, Sample.getStaticInnerPrivate());
	}
}

Wenn der Konstruktor ein Argument akzeptiert

In diesem Beispiel wird der Konstruktor ohne Argument aufgerufen. Bei einem Konstruktor wie "InnerStatic (String str)" werden Typ und Wert des Arguments zum Zeitpunkt der Erfassung angegeben.

 // Den Konstruktor holen
Constructor constructor = innerClazz.getDeclaredConstructor(new Class[]{String.class});

 // Holen Sie sich das Objekt
Object inner = constructor.newInstance("constructor");

Schließlich

Nun, weil es ein Test ist, benutze ich Reflexion, um unsichtbare Felder und Methoden wie diese aufzurufen, aber nur weil ich es nennen kann, halte ich es für eine gute Idee, Reflexion über die getestete Person zu verwenden. Ich denke nicht, dass es üblich ist, Reflektion in der Quelle des Programms selbst zu verwenden. Wenn Sie es also verwenden, ist es möglicherweise besser, es anhand des Designs zu überprüfen. (Außer wenn Sie das Framework selbst erstellen) Wenn Sie sich nicht sicher sind, sprechen Sie mit jemandem, der Sie vielleicht kennt. Insbesondere in Umgebungen, in denen Codeüberprüfungen nicht ordnungsgemäß durchgeführt werden.

Bonus Nein, ich bin gerade dabei, den Job zu wechseln, aber ich suche einen Arbeitsplatz, an dem ich meinen eigenen Code schreiben kann (auch wenn ich Neulingen technische Anleitungen gebe). Ich bin der Typ, der nicht für das Management geeignet ist. Bitte kontaktieren Sie mich, wenn Sie einen guten Arbeitsplatz zum Schreiben von Code haben.

Recommended Posts

[Java] Verweisen Sie auf und setzen Sie private Variablen mit Reflektion
Versuchen Sie, Ruby und Java in Dapr zu integrieren
So greifen Sie auf Java Private-Methoden und -Felder zu
[Java] Variablen- und Typtypen
Aufrufen von Funktionen in großen Mengen mit Java Reflection
Benennen Sie Java Excel Sheet um und legen Sie die Registerkartenfarben fest
Ich möchte Bildschirmübergänge mit Kotlin und Java machen!
Java zum Spielen mit Function
Java-Programmierung (Variablen und Daten)
So legen Sie Java-Konstanten fest
Stellen Sie mit Java eine Verbindung zur Datenbank her
Stellen Sie mit Java eine Verbindung zu MySQL 8 her
Verwendung von Java-Variablen
Festlegen von Umgebungsvariablen bei Verwendung von Payjp mit Rails
Ich möchte eine Liste mit Kotlin und Java erstellen!
Ich möchte eine Funktion mit Kotlin und Java erstellen!
Festlegen und Beschreiben von Umgebungsvariablen mit Rails zsh
Beispielcode zum Parsen von Datum und Uhrzeit mit Java SimpleDateFormat
Ich möchte verschiedene Funktionen mit Kotlin und Java implementieren!
Java mit Ramen lernen [Teil 1]
Verwenden Sie Java mit MSYS und Cygwin
Verteilte Ablaufverfolgung mit OpenCensus und Java
Persönliches Memo: Metaprogrammierung mit Java-Reflexion
[Java] Mit Arrays.asList () zu beachtende Punkte
Java Primer Series (Variationen und Typen)
[Einführung in Java] Informationen zu Variablen und Typen (Variablendeklaration, Initialisierung, Datentyp)
Ich möchte mit Kotlin und Java zum vorherigen Bildschirm zurückkehren!
Grundlagen der Java-Entwicklung ~ Schreiben von Programmen (Variablen und Typen) ~
Wagen Sie es, Kaggle mit Java herauszufordern (1)
Verwenden Sie JDBC mit Java und Scala.
[Verarbeitung × Java] Verwendung von Variablen
Ich habe versucht, mit Java zu interagieren
PDF und TIFF mit Java 8 ausgeben
Durchsuchen Sie Java und MySQL PATH mit Umgebungsvariablen [Windows-Version]
[Java] Testen Sie private Methoden mit JUnit
So benennen Sie Variablen in Java
Java, Arrays für Anfänger
Mit Java verschlüsseln und mit C # entschlüsseln
So testen Sie eine private Methode und verspotten sie teilweise in Java
Ich möchte Bilder mit REST Controller von Java und Spring anzeigen!
So erstellen Sie eine App mit einem Plug-In-Mechanismus [C # und Java]
Java8 / 9-Anfänger: Streamen Sie API-Suchtpunkte und wie Sie damit umgehen
Java für Anfänger, Variablen und Typen
So kompilieren Sie Java mit VsCode & Ant
Überwachen Sie Java-Anwendungen mit Jolokia und Hawtio
Verknüpfen Sie Java- und C ++ - Code mit SWIG
Probieren wir WebSocket mit Java und Javascript aus!
Einführung in Algorithmen mit Java-Suche (Tiefenprioritätssuche)
Java-Implementierung zum Erstellen und Lösen von Labyrinthen
[Java] Lesen und Schreiben von Dateien mit OpenCSV
[Java] Unterschiede zwischen Instanzvariablen und Klassenvariablen
[Java] Wie man Dateien ausgibt und schreibt!
So richten Sie kapt ein und verwenden es
[Java] So stellen Sie die Datums- und Uhrzeit auf 00:00:00 ein
So setzen Sie JAVA_HOME mit dem Appassembler-Maven-Plugin von Maven
Mit dem effektiven privaten Java-Konstruktor nicht unveränderlich erzwingen
Java-Programmierung (statische Klausel und "Klassenvariablen")
[Einführung in Java] Informationen zu Variablendeklarationen und -typen
So testen Sie den privaten Bereich mit JUnit