Zuvor konnten in Was Sie beim Schreiben von Java beachten sollten ** private Methoden durch Reflektion aufgerufen werden, sodass Zugriffsmodifikatoren nur zum Testen verwendet werden. Ich habe geschrieben, dass Sie es nicht löschen sollten **. Hier ist ein Beispiel.
Wenn es sich um ein Feld anstelle einer Methode handelt, schreiben Sie es wie folgt. → Private Variablen in Reflexion verweisen / setzen
2018/12/26 Hinzugefügt "Private Konstruktor aufrufen"
Wir sind uns bewusst, dass es eine Meinung gibt, dass "es von der öffentlichen Methode aufgerufen werden sollte, um die private Methode konsistent zu testen". Abhängig vom Projekt gibt es jedoch viele Fälle, die eine methodenbasierte test = private Methode enthalten. Es ist eine Regel. Jeder schreibt den Testcode entsprechend. Selbst wenn Sie es brechen, werden Sie nur aufgefordert, es neu zu schreiben. In der Geschäftslogik kann es eine öffentliche Methode in einer Klasse geben. In einem solchen Fall ist der Test ebenfalls schwierig. Es ist einfacher, einen Test für eine öffentliche Methode zu schreiben, nachdem die Verarbeitung für jede private Methode mit einem Test garantiert wurde. Aus diesem Grund liegen die Vor- und Nachteile des Testens nach einer privaten Methode außerhalb des Anwendungsbereichs.
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.
Sample.java
public class Sample {
private String strValue = null;
public Sample(String value) {
this.strValue = (value == null) ? "" : value;
}
/** 5.Rufen Sie den privaten Konstruktor auf*/
private Sample() {
}
/** 1.Aufrufen einer nicht statischen Methode*/
private boolean equals(String value) {
return this.strValue.equals(value);
}
/** 2.Eine statische Methode aufrufen*/
private static boolean isEmpty(String value) {
return (value == null || "".equals(value)) ? true : false;
}
/** 3.Aufruf ohne Rückgabewert oder Argument*/
private static void dispMessage() {
System.out.println("Hello world!");
}
/** 4.Auf Ausnahmen prüfen*/
private void setValue(String value) {
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException("argument is empty.");
}
this.strValue = value;
}
}
doPrivateMethod ist die Methode zum Aufrufen der zu testenden privaten Methode. In Typen werden die Typen der Argumente der privaten Methode in der Reihenfolge ab dem ersten Argument in einem Array gespeichert und übergeben. args übergibt die Argumente auch selbst. Da der Name der zu testenden Methode, der Typ und die Anzahl der Argumente angegeben sind, schlägt der Test fehl, wenn der Bereich durch Refactoring oder dergleichen geändert wird. (InvocationTargetException tritt auf)
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"}));
}
/**
*Nicht statischer Methodenaufruf.
*
* @param obj Getestetes Objekt
* @Parametername Name der getesteten Methode
* @Parametertypen Argumenttypen der zu testenden Methode
* @param args Argumente der zu testenden Methode
* @return Rückgabewert der nicht statischen Methode
*/
private Object doPrivateMethod(
Object obj, String name, Class[] types, Object[] args) throws Exception {
//Informieren Sie sich über die zu testende Methode
Method method = obj.getClass().getDeclaredMethod(name, types);
//Entfernen Sie die Zugriffsbeschränkungen für die zu testende Methode
method.setAccessible(true);
//Getesteter Methodenaufruf
return method.invoke(obj, args);
}
}
doStaticPrivateMethod ist die Methode zum Aufrufen der zu testenden privaten Methode. Diejenigen, die für Refactoring anfällig sind, sind die gleichen wie 1. Da es sich um einen Aufruf einer statischen Methode handelt, wird kein Objekt als Argument übergeben.
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}));
}
/**
*statischer Methodenaufruf.
*
* @Parametername Name der getesteten Methode
* @Parametertypen Argumenttypen der zu testenden Methode
* @param args Argumente der zu testenden Methode
* @Rückgabewert der statischen Methode
*/
private Object doStaticPrivateMethod(
String name, Class[] types, Object[] args) throws Exception {
//Informieren Sie sich über die zu testende Methode
Method method = Sample.class.getDeclaredMethod(name, types);
//Entfernen Sie die Zugriffsbeschränkungen für die zu testende Methode
method.setAccessible(true);
//Getesteter Methodenaufruf
return method.invoke(null, args);
}
}
assertTrue((boolean) this.doStaticPrivateMethod("isEmpty", new Class[]{String.class}, new Object[]{null}));
Wenn Sie in einer Methode mit Argumenten null übergeben möchten, fügen Sie sie in ein Array ein. Ein Array ist auch mit einem Argument erforderlich. Wenn Sie es so übergeben, wie es ist, wird es fehlschlagen.
Wenn die zu testende Methode ungültig ist, gibt es keinen Rückgabewert. (Null, auch wenn Sie versuchen, es aufzuheben) Übergeben Sie null, wenn Sie eine Methode ohne Argumente aufrufen. Im Gegensatz zu 2. muss es kein Array sein.
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);
}
}
** Aus Kommentaren hinzugefügt **
this.doStaticPrivateMethod("dispMessage", null, null);
Es wird nicht behauptet, da es sich um eine Beispielaufrufmethode handelt. Selbst beim Testen einer Void-Methode ist es wichtig, das Verarbeitungsergebnis zu überprüfen. Wenn Sie beispielsweise eine Datenbank oder Datei verarbeiten, bestätigen Sie das Ergebnis. Überprüfen Sie im Fall der Sample-Klasse, ob die an die Konsole ausgegebene Zeichenfolge korrekt ist. Zum Beispiel so.
//Standardausgabeergebnisumleitung
ByteArrayOutputStream out = new ByteArrayOutputStream();
System.setOut(new PrintStream(out));
//Getesteter Anruf
this.doStaticPrivateMethod("dispMessage", null, null);
//Behaupten
assertEquals("Hello world!" + System.lineSeparator(), out.toString());
Wenn Sie das Beispiel ausführen möchten, importieren Sie ByteArrayOutputStream und PrintStream.
Alle Aufruffehler werden mit ** InvocationTargetException ** umbrochen und ausgelöst. Daher wird die Prüfung auf im Testziel ausgelöste Ausnahmen durchgeführt, indem der von InvocationTargetException umschlossene Inhalt extrahiert wird. Wenn ein Test bestätigt, dass eine Ausnahme ausgelöst wird, wenn die Ausnahme nicht ausgelöst wird oder wenn eine andere Ausnahme als die beabsichtigte Ausnahme auftritt, schlägt der Test in JUnit fehl, sodass ** fehlschlagen (explizit ** fehlschlagen) );**Anruf.
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[]{""});
//Im Test durchgefallen
fail();
} catch (InvocationTargetException e) {
//Ausnahmetypprüfung
assertTrue(e.getCause() instanceof IllegalArgumentException);
//Überprüfung der Ausnahmemeldung
assertEquals("argument is empty.", e.getCause().getMessage());
} catch (Exception e) {
//Im Test durchgefallen
fail(e.getMessage());
}
}
}
Schreibt es nicht einen privaten Konstruktor ohne Argumente, um zu verhindern, dass er in einer statischen Klasse von außen aufgerufen wird? Das ist die Testmethode. Es wird in Projekten verwendet, bei denen "100% Deckung" eine Bedingung ist. Der Kommentar lautet "Schreiben Sie den Klassennamen mit einem vollständig qualifizierten Namen". Da die Beispielklasse diesmal nicht gepackt ist, wird nur der Klassenname beschrieben. Normalerweise denke ich, dass es ein Paket gibt, daher funktioniert es nur, wenn es sich um einen vollständig qualifizierten Namen handelt.
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 {
//Beschreiben Sie den Klassennamen als vollständig qualifizierten Namen
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);
Beschreiben Sie hier die in der Beispielklasse mit 0-Ursprung beschriebene Reihenfolge. In diesem Fall ist der private Konstruktor, den Sie testen möchten, der zweite der Sample-Klassenkonstruktoren, daher ist er "1". Wenn Sie nur einen Konstruktor zum Testen haben, ist "0" in Ordnung.
Hab ein gutes Java-Leben! Wenn etwas passiert, schreibe ich es in ein Postskriptum oder einen anderen Artikel.
Recommended Posts