Sometimes I do a single unit with JUnit, but it is troublesome to create a process to execute a private method each time, so make a note here. It's not limited to testing, but it's probably used only for test code.
Params.java
package com.example.demo.util;
import java.lang.reflect.Method;
public class ReflectionUtil {
/**
*Execute a private method (no arguments).
* @Instance that executes the param obj method
* @param methodName method name
* @param params argument
* @return value of the return method
* @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);
}
/**
*Execute a private method (with arguments).
* @Instance that executes the param obj method
* @param methodName method name
* @param params argument
* @return value of the return method
* @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());
}
}
By the way, getDeclaredMethod gets a method object from a java.lang.Class object, so you don't need to instantiate it for a static method. So you can pass the class directly to the first argument of invokePrivate and execute getDeclaredMethod.
A class for grouping the arguments required to execute a private method with the above arguments.
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<>();
}
/**
*Constructor that specifies arguments at the same time as initialization.
* @param type
* @param arg
*/
public <T> Params(Class<T> type, T arg) {
this();
add(type, arg);
}
/**
*Set arguments and their types.
* @param type
* @param arg
*/
public <T> void add(Class<T> type, T arg) {
paramList.add(new Param(type, arg));
}
/**
*Returns the set argument type as an array.
* @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;
}
/**
*Returns the set argument as an array.
* @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;
}
/**
*A class that represents one argument.<br />
*It has an argument object and its type as attributes.
*
*/
@Data
private class Param {
private Class<?> type;
private Object arg;
<T> Param(Class<T> type, T arg) {
this.type = type;
this.arg = arg;
}
}
}
--Private method to be tested
Prepare a private method with arguments as appropriate.
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 "Done!";
}
UtilTest.java
@Test
public void test1() {
AService test = new AService();
//Try to specify the first argument in the constructor
Params params = new Params(int.class, 1);
//Then add with add
params.add(Long.class, 20L);
params.add(String.class, "Third argument");
try {
//Run
String ret = (String) ReflectionUtil.invokePrivate(test, "doSomthing", params);
System.out.println(ret);
} catch (Exception e) {
e.printStackTrace();
fail();
}
}
When actually using it, it is easier to see invokePrivate if it is statically imported.
Execution result
1
20
Third argument
Done!
By the way,
UtilTest.java
/**
*If null is specified instead of params.
*/
@Test
public void testParamsNull() {
AServices = new AService();
try {
ReflectionUtil.invokePrivate(s, TARGET_METHOD, null);
fail();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*When the arguments set in params do not match.
*/
@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();
}
}
Execution result 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)
:
Execution result 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)
:
that's all.
Recommended Posts