Manchmal mache ich eine einzelne Einheit mit JUnit, aber es ist mühsam, einen Prozess zu erstellen, um jedes Mal eine private Methode auszuführen. Notieren Sie sich dies hier. Es ist nicht auf das Testen beschränkt, sondern wird wahrscheinlich nur für Testcode verwendet.
Params.java
package com.example.demo.util;
import java.lang.reflect.Method;
public class ReflectionUtil {
/**
*Führen Sie eine private Methode aus (kein Argument).
* @Instanz, die die param obj-Methode ausführt
* @param methodName Methodenname
* @param params Argument
* @Rückgabewert der Rückgabemethode
* @throws Exception
*/
public static Object invokePrivate(Object obj, String methodName) throws Exception {
Class<?> clazz = obj.getClass();
Method method = clazz.getDeclaredMethod(methodName);
method.setAccessible(true);
return method.invoke(obj);
}
/**
*Führen Sie eine private Methode aus (mit Argumenten).
* @Instanz, die die param obj-Methode ausführt
* @param methodName Methodenname
* @param params Argument
* @Rückgabewert der Rückgabemethode
* @throws Exception
*/
public static Object invokePrivate(Object obj, String methodName, Params params) throws Exception {
if(params == null ){
throw new NullPointerException("params is required");
}
Class<?> clazz = obj.getClass();
Method method = clazz.getDeclaredMethod(methodName, params.getTypes());
method.setAccessible(true);
return method.invoke(obj, params.getArgs());
}
}
GetDeclaredMethod ruft das Methodenobjekt übrigens aus dem Objekt java.lang.Class ab, sodass Sie es für statische Methoden nicht instanziieren müssen. Sie können die Klasse also direkt an das erste Argument von invokePrivate übergeben und getDeclaredMethod ausführen.
Eine Klasse zum Sammeln der Argumente, die zum Ausführen einer privaten Methode mit den obigen Argumenten erforderlich sind.
Params.java
package com.example.demo.util;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
public class Params {
private List<Param> paramList;
public Params() {
paramList = new ArrayList<>();
}
/**
*Konstruktor, der Argumente gleichzeitig mit der Initialisierung angibt.
* @param type
* @param arg
*/
public <T> Params(Class<T> type, T arg) {
this();
add(type, arg);
}
/**
*Legen Sie Argumente und ihre Typen fest.
* @param type
* @param arg
*/
public <T> void add(Class<T> type, T arg) {
paramList.add(new Param(type, arg));
}
/**
*Gibt den festgelegten Argumenttyp als Array zurück.
* @return
*/
public Class<?>[] getTypes() {
Class<?>[] types = new Class[paramList.size()];
for (int i = 0; i < paramList.size(); i++) {
types[i] = paramList.get(i).getType();
}
return types;
}
/**
*Gibt das set-Argument als Array zurück.
* @return
*/
public Object[] getArgs() {
Object[] args = new Object[paramList.size()];
for (int i = 0; i < paramList.size(); i++) {
args[i] = paramList.get(i).getArg();
}
return args;
}
/**
*Klasse, die ein Argument darstellt.<br />
*Es hat ein Argumentobjekt und seinen Typ als Attribute.
*
*/
@Data
private class Param {
private Class<?> type;
private Object arg;
<T> Param(Class<T> type, T arg) {
this.type = type;
this.arg = arg;
}
}
}
--Privatmethode zum Testen
Bereiten Sie eine private Methode mit einem geeigneten Argument vor.
Test.java
private String doSomthing(int i, Long l, String str){
System.out.println(Integer.toString(i));
System.out.println(l.toString());
System.out.println(str);
return "Erledigt!";
}
UtilTest.java
@Test
public void test1() {
AService test = new AService();
//Versuchen Sie, das erste Argument im Konstruktor anzugeben
Params params = new Params(int.class, 1);
//Dann mit add hinzufügen
params.add(Long.class, 20L);
params.add(String.class, "Drittes Argument");
try {
//Lauf
String ret = (String) ReflectionUtil.invokePrivate(test, "doSomthing", params);
System.out.println(ret);
} catch (Exception e) {
e.printStackTrace();
fail();
}
}
Bei der tatsächlichen Verwendung ist invokePrivate leichter zu erkennen, wenn es statisch importiert wird.
Ausführungsergebnis
1
20
Drittes Argument
Erledigt!
Apropos,
UtilTest.java
/**
*Wenn null anstelle von params angegeben wird.
*/
@Test
public void testParamsNull() {
AServices = new AService();
try {
ReflectionUtil.invokePrivate(s, TARGET_METHOD, null);
fail();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*Wenn die in params festgelegten Argumente nicht übereinstimmen.
*/
@Test
public void testParamsInvalid() {
AService s = new AService();
Params params = new Params(int.class, 1);
params.add(Long.class, 20L);
try {
ReflectionUtil.invokePrivate(s, TARGET_METHOD, params);
fail();
} catch (Exception e) {
e.printStackTrace();
}
}
Ausführungsergebnis testParamsNull()
java.lang.NullPointerException: params is required
at com.example.demo.util.ReflectionUtil.invokePrivate(ReflectionUtil.java:32)
at com.example.demo.UtilTest.test1(UtilTest.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
:
Ausführungsergebnis testParamsInvalid()
java.lang.NoSuchMethodException: com.example.demo.service.AService.doSomthing(int, java.lang.Long)
at java.lang.Class.getDeclaredMethod(Class.java:2122)
at com.example.demo.util.ReflectionUtil.invokePrivate(ReflectionUtil.java:35)
at com.example.demo.UtilTest.test1(UtilTest.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
:
das ist alles.
Recommended Posts