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