private Methods
:我知道如何:
private Fields
:我知道如何:
private Fields
:我知道如何:
private Constructors
:我知道如何:
(可用于在单一模式中创建私有构造函数的新实例,同时保持实例Field为null)
我不知道的,以及我想知道的事情:
我应该更改代码的内容和方式?
TestMethodsClass中的这部分:
if(Modifier.isStatic(field.getModifiers())){
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.STATIC);
}
或者我在UnitTest-Class中进行的调用:
// Getting private STATIC String myString of the class MyClass and set it to a local variable
// public static call equivalent: String localString = myClassInstance.myString;
// public Getter call equivalent: String localString = myClassInstance.getMyString();
try {
String localString = TestMethodsClass.getPrivateField(myClassInstance, "myString");
}
catch (MyUnitTestException ex) {
Assert.fail("setPrivateField caused an Exception: " + ex.getThrownException());
}
我目前的课程以及如何调用它的一些示例:
TestMethodsClass.java:
package unittests;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class TestMethodsClass
{
// Test method to run a private void Method from a class
public static void runPrivateVoidMethod(Object ob, String methodName, Class<?>[] paramTypes, Object[] paramValues) throws MyUnitTestException{
try {
Method method = null;
if(paramTypes == null){
method = ob.getClass().getDeclaredMethod(methodName, (Class[])null);
if(method != null){
method.setAccessible(true);
method.invoke(ob);
}
}
else{
if(paramValues != null && paramTypes.length == paramValues.length){
method = ob.getClass().getDeclaredMethod(methodName, paramTypes);
if(method != null){
method.setAccessible(true);
method.invoke(ob, paramValues);
}
}
else
runPrivateReturnMethod(ob, methodName, null, null);
}
}
catch (NoSuchMethodException ex){
throw new MyUnitTestException(ex);
}
catch (IllegalAccessException ex){
throw new MyUnitTestException(ex);
}
catch (IllegalArgumentException ex){
throw new MyUnitTestException(ex);
}
catch (InvocationTargetException ex) {
throw new MyUnitTestException(ex);
}
}
// Test method to run a private Method that returns something from a class
public static Object runPrivateReturnMethod(Object ob, String methodName, Class<?>[] paramTypes, Object[] paramValues) throws MyUnitTestException{
Object returnObject = null;
try {
Method method = null;
if(paramTypes == null){
method = ob.getClass().getDeclaredMethod(methodName, (Class[])null);
if(method != null){
method.setAccessible(true);
returnObject = method.invoke(ob);
}
}
else{
if(paramValues != null && paramTypes.length == paramValues.length){
method = ob.getClass().getDeclaredMethod(methodName, paramTypes);
if(method != null){
method.setAccessible(true);
returnObject = method.invoke(ob, paramValues);
}
}
else
returnObject = runPrivateReturnMethod(ob, methodName, null, null);
}
}
catch (NoSuchMethodException ex){
throw new MyUnitTestException(ex);
}
catch (IllegalAccessException ex){
throw new MyUnitTestException(ex);
}
catch (IllegalArgumentException ex){
throw new MyUnitTestException(ex);
}
catch (InvocationTargetException ex) {
throw new MyUnitTestException(ex);
}
return returnObject;
}
// Test method to set a private Field from a class
public static void setPrivateField(Object ob, String fieldName, Object value) throws MyUnitTestException{
try {
Field field = ob.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
if(Modifier.isStatic(field.getModifiers())){
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.STATIC);
}
if(Modifier.isFinal(field.getModifiers())){
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
}
field.set(ob, value);
}
catch (NoSuchFieldException ex){
throw new MyUnitTestException(ex);
}
catch (IllegalAccessException ex){
throw new MyUnitTestException(ex);
}
catch (IllegalArgumentException ex){
throw new MyUnitTestException(ex);
}
}
// Test method to access a private Field from a class
public static Object getPrivateField(Object ob, String fieldName) throws MyUnitTestException{
Object returnObject = null;
try {
Field field = ob.getClass().getDeclaredField(fieldName);
if(Modifier.isStatic(field.getModifiers())){
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.STATIC);
}
returnObject = field.get(ob);
}
catch (NoSuchFieldException ex) {
throw new MyUnitTestException(ex);
}
catch (IllegalAccessException ex) {
throw new MyUnitTestException(ex);
}
catch (IllegalArgumentException ex) {
throw new MyUnitTestException(ex);
}
return returnObject;
}
// test method to access a private Constructor (of a Singleton class)
public static Object getPrivateConstuctor(Object ob, Class<?>[] paramTypes, Object[] paramValues) throws MyUnitTestException{
Object returnObject = null;
try {
Constructor<?> constructor = null;
if(paramTypes == null){
constructor = ob.getClass().getDeclaredConstructor(paramTypes);
if(constructor != null){
constructor.setAccessible(true);
returnObject = constructor.newInstance();
}
}
else{
if(paramValues != null && paramTypes.length == paramValues.length){
constructor = ob.getClass().getDeclaredConstructor(paramTypes);
if(constructor != null){
constructor.setAccessible(true);
returnObject = constructor.newInstance(paramValues);
}
}
else
getPrivateConstuctor(ob, null, null);
}
}
catch (NoSuchMethodException ex) {
throw new MyUnitTestException(ex);
}
catch (InstantiationException ex) {
throw new MyUnitTestException(ex);
}
catch (IllegalAccessException ex) {
throw new MyUnitTestException(ex);
}
catch (IllegalArgumentException ex) {
throw new MyUnitTestException(ex);
}
catch (InvocationTargetException ex) {
throw new MyUnitTestException(ex);
}
return returnObject;
}
}
(这里是seply的getPrivateField,因为这是它的方法。):
// Test method to access a private Field from a class
public static Object getPrivateField(Object ob, String fieldName) throws MyUnitTestException{
Object returnObject = null;
try {
Field field = ob.getClass().getDeclaredField(fieldName);
if(Modifier.isStatic(field.getModifiers())){
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.STATIC);
}
returnObject = field.get(ob);
}
catch (NoSuchFieldException ex) {
throw new MyUnitTestException(ex);
}
catch (IllegalAccessException ex) {
throw new MyUnitTestException(ex);
}
catch (IllegalArgumentException ex) {
throw new MyUnitTestException(ex);
}
return returnObject;
}
MyUnitTestException.java:
package unittests;
public class MyUnitTestException extends Exception
{
private static final long serialVersionUID = 1L;
private Throwable thrownException;
public MyUnitTestException(Throwable ex){
super(ex);
thrownException = ex;
}
public String getThrownException(){
if(thrownException != null)
return thrownException.getClass().getName();
else
return null;
}
}
示例用法:
将MyClass类的private int myInteger设置为3:
// public static call equivalent: myClassInstance.myInteger = 3;
// public Setter call equivalent: myClassInstance.setMyInteger(3);
try {
TestMethodsClass.setPrivateField(myClassInstance, "myInteger", 3);
}
catch (MyUnitTestException ex) {
Assert.fail("setPrivateField caused an Exception: " + ex.getThrownException());
}
获取类MyClass的私有String myString并将其设置为局部变量:
// public static call equivalent: String localString = myClassInstance.myString;
// public Getter call equivalent: String localString = myClassInstance.getMyString();
try {
String localString = TestMethodsClass.getPrivateField(myClassInstance, "myString");
}
catch (MyUnitTestException ex) {
Assert.fail("setPrivateField caused an Exception: " + ex.getThrownException());
}
获取MyClass()的私有(构造函数)并将其设置为局部变量:
// public call equivalent: MyClass localMyClassInstance = new MyClass();
try {
MyClass localMyClassInstance = TestMethodsClass.getPrivateConstructor(myClassInstance, null, null);
}
catch (MyUnitTestException ex) {
Assert.fail("setPrivateField caused an Exception: " + ex.getThrownException());
}
使用MyOtherObject作为参数运行私有void Setter-Method:
// public call equivalent: myObjectInstance.setMyOtherClass(myOtherClassInstance);
try {
TestMethodsClass.runPrivateVoidMethod(MyClass, "setMyOtherClass", new Class<?>[]{ MyOtherClass.class }, new Object[]{ myOtherClassInstance });
}
catch (MyUnitTestException ex) {
Assert.fail("setPrivateField caused an Exception: " + ex.getThrownException());
}
PS:我只在我的UnitTests中使用它。
编辑1:
我的单位测试:
Controller controller = Controller.getInstance();
...
try {
Controller cInstance = (Controller)TestMethodsClass.getPrivateField(controller, "instance");
}
catch (MyUnitTestException ex){
Assert.fail("getPrivateField caused an Exception: " + ex.getThrownException());
}
instance
- Controller的字段:
// Singleton class where we store all lists of the Models
public class Controller
{
// Default field used by the Singleton Design Pattern
private static Controller instance;
...
// This Constructor is private since this is a Singleton class
private Controller() {
...
}
// Default method used by the Singleton Design Pattern
public static Controller getInstance(){
if(instance == null)
instance = new Controller();
return instance;
}
...
}
这会导致catch中的以下UnitTest.error。
junit.framework.AssertionFailedError: getPrivateField caused an Exception: java.lang.IllegalAccessException
at junit.framework.Assert.fail(Assert.java:47)
at controllers.ControllerUnitTest.controllerTest(ControllerUnitTest.java:69)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:110)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
提前感谢您的回复。
答案 0 :(得分:2)
- 获取任何类型的
private static
Field
并将其设置为本地(非静态)变量- 获取任何类型的
private static final
Field
并将其设置为本地(非静态)变量
Field privateStaticField = ...;
privateStaticField.setAccessible(true);
Object localVariable = privateStaticField.get(null);
同样适用于final
字段。
如果您的意思是将字段的值设置为局部变量的值
Field privateStaticField = ...;
privateStaticField.setAccessible(true);
Object localVariable = ...;
privateStaticField.set(null, localVariable);
对于final
成员,由于必须使用修饰符,因此会稍微复杂一些。如果你的字段是一个常量表达式会变得更糟。请参阅here。