Thursday, May 19, 2011

Testing Private methods using Reflection

Testing private methods using JUnit is a tricky thing. We have different ways to do so, but I feel using reflection is the better way of doing things. Below is a utility class which invokes the private methods using reflection and return the expected results from the private method.

Calculator.java

package com.dev.junit.test;
public class Calculator {

private int privateField = 0;  
private Integer calculateSimpleInterest(Integer principal, Integer term, Integer rateOfInterest){
        Integer interest = principal*term*rateOfInterest/100;
        return interest;
    }}

PrivateUtility.java 

package com.dev.junit.test;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class PrivateUtility {
   
    public static Object invokePrivate(String methodName, Object object, Class[] signature, Object[] values)
    throws NoSuchMethodException
    {
        Class pvtClass = object.getClass();
        Method method = null;
        while (method == null) {
            try {
                method = pvtClass.getDeclaredMethod( methodName, signature );
            } catch (NoSuchMethodException e) {
                pvtClass = pvtClass.getSuperclass();
                if (pvtClass == null) {
                    throw e;
                }
            }
        }
        method.setAccessible(true);
        try {
            return method.invoke(object, values );
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new NoSuchMethodException( e.toString() );
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            throw new RuntimeException( e.getCause() );
        }
    }
   
    public static void setPrivate(Object object, String fieldName, Object value)
    throws NoSuchFieldException
    {
        try {
            Field field = null;
            Class instanceClass = object.getClass();
            while (field == null) {
                try {
                    field = instanceClass.getDeclaredField( fieldName );
                } catch (NoSuchFieldException e) {
                    instanceClass = instanceClass.getSuperclass();
                    if (instanceClass == null) {
                        throw e;
                    }   }    }
            field.setAccessible(true);
            field.set(object, value);
        } catch (SecurityException e) {
            e.printStackTrace();
            throw new NoSuchFieldException( "Unable to set field [" + fieldName + "]: " + e.toString() );
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            throw new NoSuchFieldException( "Unable to set field [" + fieldName + "]: " + e.toString() );
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new NoSuchFieldException( "Unable to set field [" + fieldName + "]: " + e.toString() );
        }
    }

   
    public static Integer getPrivate(Object object, String fieldName )
    throws NoSuchFieldException
    {
        try {
            Class instanceClass = object.getClass();
            Field field = null;
            while (field == null) {
                try {
                    field = instanceClass.getDeclaredField( fieldName );
                } catch (NoSuchFieldException e) {
                    instanceClass = instanceClass.getSuperclass();
                    if (instanceClass == null) {
                        throw e;
                    }  }  }
            field.setAccessible(true);
            return (Integer) field.getInt(object);
        } catch (SecurityException e) {
            e.printStackTrace();
            throw new NoSuchFieldException( "Unable to access field [" + fieldName + "]: " + e.toString() );
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new NoSuchFieldException( "Unable to access field [" + fieldName + "]: " + e.toString() );
        }
    }} 
CalculatorPrivateTest.java


package com.dev.junit.test;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class CalculatorPrivateTest {

    @Test
    public void testCalculateSimpleInterest(){
        Calculator calc = new Calculator();
        try {
            // invoke private method with object parameters
            Object obj = PrivateUtility.invokePrivate("calculateSimpleInterest", calc, new Class[]{Integer.class,Integer.class,Integer.class}, new Object[]{1000,10,12});
            int i = (Integer)obj;
            assertEquals(1200, i);
          
            // invoke private method with object parameters
            Object obj1 = PrivateUtility.invokePrivate("calculateSimpleInterestPrimitives", calc, new Class[]{Integer.TYPE,Integer.TYPE,Integer.TYPE}, new Object[]{2000,10,12});
            int i1 = (Integer)obj1;
            assertEquals(2400, i1);
          
            //set the value to private fields
            PrivateUtility.setPrivate(calc, "privateField", 200);
          
            //check the value to private fields
            int pvtValue = (Integer)PrivateUtility.getPrivate(calc, "privateField");
            assertEquals(200, pvtValue);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    } }

No comments:

Post a Comment