单元测试的时候,有时为了测试,不得不把一些本来应该private的域或者属性改成了package的,很不爽。到网上找一圈访问private域或方法的类库,都不太满意,太复杂了不是我想要的。于是自己动手丰衣足食吧!看代码:
public class PrivateAccessor {
public static void set(Object target, String fieldName, Object value) {
try {
Field field = findFieldRecursively(target.getClass(), fieldName);
field.setAccessible(true);
field.set(target, value);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static void set(Class<?> clazz, String fieldName, Object value) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(null, value);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static Object get(Object target, String fieldName) {
try {
Field field = findFieldRecursively(target.getClass(), fieldName);
field.setAccessible(true);
return field.get(target);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static Object get(Class<?> clazz, String fieldName) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static Object invoke(Object object, String methodName, Class<?>[] argumentTypes, Object... args) {
try {
Method method = findMethodRecursively(object.getClass(), methodName, argumentTypes);
method.setAccessible(true);
return method.invoke(object, args);
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static Object invoke(Class<?> clazz, String methodName, Class<?>[] argumentTypes, Object... args) {
try {
Method method = clazz.getDeclaredMethod(methodName, argumentTypes);
method.setAccessible(true);
return method.invoke(null, args);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private static Field findFieldRecursively(Class<?> clazz, String name) {
Field field = null;
Class<?> clazzToFind = clazz;
while (field == null) {
try {
field = clazzToFind.getDeclaredField(name);
} catch (NoSuchFieldException e) {
;
}
if (field != null) {
return field;
}
clazzToFind = clazzToFind.getSuperclass();
if (clazzToFind.equals(Object.class)) {
throw new RuntimeException("field not found, field: " + name);
}
}
if (field == null) {
throw new RuntimeException("field not found, field: " + name);
}
return field;
}
private static Method findMethodRecursively(Class<?> clazz, String name, Class<?>[] argumentTypes) {
Method method = null;
Class<?> clazzToFind = clazz;
while (method == null) {
try {
method = clazzToFind.getDeclaredMethod(name, argumentTypes);
} catch (NoSuchMethodException e) {
;
}
if (method != null) {
return method;
}
clazzToFind = clazzToFind.getSuperclass();
if (clazzToFind.equals(Object.class)) {
throw new RuntimeException("method not found, method: " + name);
}
}
if (method == null) {
throw new RuntimeException("method not found, method: " + name);
}
return method;
}
}
使用方法很简单,看单元测试:
public class PrivateAccessorTest {
@Test
public void test_set() {
TestObject testObject = new TestObject();
PrivateAccessor.set(testObject, "name", "sulong");
assertEquals("sulong", testObject.getName());
PrivateAccessor.set(testObject, "age", 1);
assertEquals(1, testObject.getAge());
}
@Test
public void test_set_sub() {
SubTestObject testObject = new SubTestObject();
PrivateAccessor.set(testObject, "age", 2);
assertEquals(2, testObject.getAge());
}
@Test
public void test_set_static() {
TestObject.setNumber(100L);
PrivateAccessor.set(TestObject.class, "number", 110L);
assertEquals(110L, (long) TestObject.getNumber());
}
@Test
public void test_get() {
TestObject testObject = new TestObject();
testObject.setName("sulong");
assertEquals("sulong", PrivateAccessor.get(testObject, "name"));
testObject.setAge(1);
assertEquals(1, PrivateAccessor.get(testObject, "age"));
}
@Test
public void test_get_sub() {
SubTestObject testObject = new SubTestObject();
testObject.setAge(1);
assertEquals(1, PrivateAccessor.get(testObject, "age"));
}
@Test
public void test_get_static() {
TestObject.setNumber(100L);
assertEquals(100L, PrivateAccessor.get(TestObject.class, "number"));
}
@Test
public void test_invoke() {
TestObject testObject = new TestObject();
testObject.setAge(1);
PrivateAccessor.invoke(testObject, "addAge", new Class[]{});
assertEquals(2, testObject.getAge());
assertEquals(12, PrivateAccessor.invoke(testObject, "getAgePlusTen", new Class[]{}));
assertEquals(13, PrivateAccessor.invoke(testObject, "addSomeAge", new Class[]{Integer.TYPE}, 11));
}
@Test
public void test_invoke_sub() {
SubTestObject testObject = new SubTestObject();
testObject.setAge(1);
PrivateAccessor.invoke(testObject, "addAge", new Class[]{});
assertEquals(2, testObject.getAge());
assertEquals(12, PrivateAccessor.invoke(testObject, "getAgePlusTen", new Class[]{}));
assertEquals(13, PrivateAccessor.invoke(testObject, "addSomeAge", new Class[]{Integer.TYPE}, 11));
}
@Test
public void test_invoke_static() {
assertEquals(2, PrivateAccessor.invoke(TestObject.class, "add", new Class[]{Integer.TYPE, Integer.TYPE}, 1, 1));
}
}
class TestObject {
private String name;
private int age;
private static Long number;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private void addAge() {
this.age++;
}
private int getAgePlusTen() {
return this.age + 10;
}
private int addSomeAge(int some) {
return this.age + some;
}
private static int add(int a, int b) {
return a + b;
}
public static Long getNumber() {
return number;
}
public static void setNumber(Long number) {
TestObject.number = number;
}
}
class SubTestObject extends TestObject {
}