我有以下三个public static methods
类:
package unittests;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestMethodsClass
{
// Test method to run a private void Method from a class
public static void runPrivateVoidMethod(Object ob, String methodName, Class<?>[] parameters){
try {
Method method = null;
if(parameters == null){
Class<?>[] nullParameter = (Class[])null;
method = ob.getClass().getDeclaredMethod(methodName, nullParameter);
}
else
method = ob.getClass().getDeclaredMethod(methodName, parameters);
if(method != null){
method.setAccessible(true);
method.invoke(ob);
}
}
catch (NoSuchMethodException ex){
ex.printStackTrace();
}
catch (IllegalAccessException ex){
ex.printStackTrace();
}
catch (IllegalArgumentException ex){
ex.printStackTrace();
}
catch (InvocationTargetException ex) {
ex.printStackTrace();
}
}
// Test method to run a private Method that returns something from a class
public static Object runPrivateReturnMethod(Object ob, String methodName, Class<?>[] parameters){
Object returnObject = null;
try {
Method method = null;
if(parameters == null){
Class<?>[] nullParameter = (Class[])null;
method = ob.getClass().getDeclaredMethod(methodName, nullParameter);
}
else
method = ob.getClass().getDeclaredMethod(methodName, parameters);
if(method != null){
method.setAccessible(true);
returnObject = method.invoke(ob);
}
}
catch (NoSuchMethodException ex){
ex.printStackTrace();
}
catch (IllegalAccessException ex){
ex.printStackTrace();
}
catch (IllegalArgumentException ex){
ex.printStackTrace();
}
catch (InvocationTargetException ex) {
ex.printStackTrace();
}
return returnObject;
}
// Test method to access a private Field from a class
public static void setPrivateField(Object ob, String fieldName, Object value){
try {
Field field = ob.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(ob, value);
}
catch (NoSuchFieldException ex){
ex.printStackTrace();
}
catch (IllegalAccessException ex){
ex.printStackTrace();
}
catch (IllegalArgumentException ex){
ex.printStackTrace();
}
}
}
这些方法的目的是能够从UnitTest-class
中调用private methods
或在MyObjectInstance中设置private fields
。一些例子:
// public method equivalent-call: myObjectInstance.doSomething();
TestMethodsClass.runPrivateVoidMethod(myObjectInstance, "doSomething", null);
// public method equivalent-call: myObjectInstance.doSomething(String s);
TestMethodsClass.runPrivateVoidMethod(myObjectInstance, "doSomething", ?¿?¿?¿);
// public method equivalent-call: boolean b = myObjectInstance.doSomethingWithBooleanReturn();
boolean b = (boolean)TestMethodsClass.runPrivateReturnMethod(myObjectInstance, "doSomethingWithBooleanReturn", null);
// public method equivalent-call: String s = myObjectInstance.doSomethingWithStringReturn();
String s = (String)TestMethodsClass.runPrivateReturnMethod(myObjectInstance, "doSomethingWithStringReturn", null);
// public method equivalent-call: MyOtherObject moj = myObjectInstance.doSomethingWithMyOtherObjectReturn();
MyOtherObject moj = (MyOtherObject)TestMethodsClass.runPrivateReturnMethod(myObjectInstance, "doSomethingWithMyOtherObjectReturn", null);
// public method equivalent-call: boolean b = myObjectInstance.doSomethingWithBooleanReturn(String s);
boolean b = TestMethodsClass.runPrivateReturnMethod(myObjectInstance, "doSomethingWithMyOtherObjectReturn", ?¿?¿?¿);
// private boolean b;
// In-Object public field equivalent-set: b = true;
TestMethodsClass.setPrivateField(myObjectInstance, "b", true);
// private String s;
// In-Object public field equivalent-set: s = "a string";
TestMethodsClass.setPrivateField(myObjectInstance, "s", "a string");
一切都是我想要的,除了一件事:我怎么把parameters
?那么,在上面的例子中我应该用什么来代替?¿?¿?¿
呢?(我应该如何改变我的public static methods
,以能够使用parameters
?)
parameters
(没有结果)。有些没有给出错误,但没有被设置(我已经使用设置方法来测试parameters
),有些给出错误(如int
):
// This gives no errors, but doesn't work
new Class<?>[]{ myOtherObjectInstance.getClass() }) // <- parameter
// Error: The method runPrivateVoidMethod(Object, String, Class<?>[]) in the type TestMethodsClass is not applicable for the arguments (MyOtherObjectInstance, String, int)
int i = 5;
i // <- parameter
// Error: Type mismatch: cannot convert from int to Class<?>
int i = 5;
new Class<?>[]{ i } // <- parameter
// Error: Type mismatch: cannot convert from int to Class<?>
int i = 5;
new Class<?>[]{ (Class<?>)i } <- parameter
// This gives no errors,
int[] iArray = new int[1];
iArray[0] = 5;
new Class<?>[]{ array.getClass() } // <- parameter
最好我只是想把一些东西(如int
, String
, MyOtherObjectInstance
, int[]
等)和cast/convert
, public static methods
中的parameters
到可用的Class<?>[]
参数。
编辑1:
Sanjeev的解决方案很有希望,但仍然不起作用。以下是对方法的更改:
// Test method to run a private void Method from a class
public static void runPrivateVoidMethod(Object ob, String methodName, Class<?>[] paramTypes, Object[] paramValues){
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){
// TODO: Check if the paramTypes are in the same order as the paramValues
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){
ex.printStackTrace();
}
catch (IllegalAccessException ex){
ex.printStackTrace();
}
catch (IllegalArgumentException ex){
ex.printStackTrace();
}
catch (InvocationTargetException ex) {
ex.printStackTrace();
}
}
// 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){
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){
// TODO: Check if the paramTypes are in the same order as the paramValues
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){
ex.printStackTrace();
}
catch (IllegalAccessException ex){
ex.printStackTrace();
}
catch (IllegalArgumentException ex){
ex.printStackTrace();
}
catch (InvocationTargetException ex) {
ex.printStackTrace();
}
return returnObject;
}
这里是我使用的UnitTest:
public void testOrderedProductList(){
// Arrange
int amount = 6;
// First product used in Constructor
Product product1 = new Product();
product1.setProductId(54);
...
OrderedProduct orderedProduct = new OrderedProduct(product1, amount);
// Second product used in the setProduct method
Product product2 = new Product();
product2.setProductId(12);
// Invoke
// HERE IS THE CALL TO THE runPrivateVoidMethod
TestMethodsClass.runPrivateVoidMethod(orderedProduct, "setProduct", new Class<?>[]{ Product.class }, new Object[]{ product2 });
Product p = orderedProduct.getProduct();
...
// Assert
//assertNotNull("product should not be null", p);
assertTrue("product should be a Product-instance", p instanceof Product);
assertEquals("product should equal the set product", product2, p);
...
}
在assertEquals("product should equal the set product", product2, p);
处失败(期望<Product {ProductId=12, ... }>
,但<Product {ProductId=54, ... }>
)
应Sanjeev的要求;Product和OrderedProduct类:
package models;
import business.V;
import android.util.Log;
public class Product
{
private int ProductId;
private String Name;
private int CategoryId;
private double Price;
private boolean Visible;
private int check_option;
public Product(){
check_option = 0;
}
// Overriding this class' toString method for print-out purposes
@Override
public String toString(){
return "Product {" +
"ProductId=" + ProductId + ", " +
"Name=" + Name + ", " +
"CategoryId=" + CategoryId + ", " +
"Price=" + Price + ", " +
"Visible=" + Visible + ", " +
"check_option=" + check_option +
"}";
}
// Getter and Setter of the ProductId
public void setProductId(int id){
if(id > 0)
ProductId = id;
else
ProductId = 0;
}
public int getProductId(){
return ProductId;
}
// Getter and Setter of the Name
public void setName(String n){
if(V.notNull(n, true))
Name = n;
else
Name = null;
}
public String getName(){
return Name;
}
// Getter and Setter of the CategoryId
public void setCategoryId(int id){
if(id > 0)
CategoryId = id;
else
CategoryId = 0;
}
public int getCategoryId(){
return CategoryId;
}
// Getter and Setter of the Price
public void setPrice(double p){
if(p > 0.00)
Price = p;
else
p = 0.00;
}
public double getPrice(){
return Price;
}
// Getter and Setter of the Visible
public void setVisible(boolean v){
Visible = v;
}
public boolean getVisible(){
return Visible;
}
// Getter and Setter of the CheckOption
public void setCheckOption(int o){
Log.i("PRODUCT CHECK", "TEST - Product (" + ProductId + ") check option changed from " + check_option + " to " + o);
if(o >= 0 && o < Config.NUMBER_OF_CHECK_OPTIONS)
check_option = o;
else
check_option = 0;
}
public int getCheckOption(){
return check_option;
}
}
package models;
public class OrderedProduct
{
private Product Product;
private int Amount;
public OrderedProduct(Product p, int a){
setProduct(p);
setAmount(a);
}
// Overriding this class' toString method for print-out purposes
@Override
public String toString(){
return "OrderedProduct {" +
"Product=" + Product + ", " +
"Amount=" + Amount +
"}";
}
// Getter and Setter of the Product
// (The Setter is private since we only use it in the Constructor)
private void setProduct(Product p){
Product = p;
}
public Product getProduct(){
return Product;
}
// Getter and Setter of the Amount
public void setAmount(int a){
if(a >= 0)
Amount = a;
else
Amount = 0;
}
public int getAmount(){
return Amount;
}
}
提前感谢您的回复。
您需要另一个参数将您的对象值传递给被调用的方法。
所以说你需要添加另一个参数到你的runPrivateVoidMethod类型为Object[]
public static void runPrivateVoidMethod(Object ob, String methodName, Class<?>[] paramTypes, Object[] paramvalues)
注意:paramType和paramValues的大小必须匹配,并且paramValues必须包含指定索引处的值,该值必须与paramTypes中同一索引上定义的值类型相同。
使用
获取方法 method = ob.getClass().getDeclaredMethod(methodName, paramTypes);
然后使用方法#invoke(Object obj,Object…)参数)将参数传递给被调用的方法。
method.invoke(ob,paramValues);