Android/Java单元测试-如何使用Java .lang.reflect. method中的参数



我有以下三个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);

相关内容

  • 没有找到相关文章

最新更新