• Private method is a which can be invoked by code in the same class. It is not inherited by subclasses.
  • A field is a class, interface, or enum with an associated value.
  • Methods in the java.lang.reflect.Field class can retrieve information about the field, such as its name, type, modifiers, and annotations.
  • Java inner class or nested class is a class i.e. declared inside the class or interface. We use inner classes to logically group classes and interfaces in one place so that it can be more readable and maintainable. Additionally, it can access all the members of outer class including private data members and methods.

  • A legacy application, we are not allowed to change the visibility of our methods, the best way to test private methods is to use reflection.
  • Internally we’re using helpers to get/set private and private static variables as well as invoke private and private static methods.
  • The following patterns related to the private methods and fields. We can’t change private static final variables through reflection.
Java Code
Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);
[ad type=”banner”]

And for fields:

Java Code
Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

Notes:

1. targetClass.getDeclaredMethod(methodName, argClasses) is looks like private methods. The same thing applies for getDeclaredField.
2. The setAccessible(true) is required.

Two examples of where we need to test a private method:

Decryption routines –

we would not want to make them visible to anyone to see just for the sake of testing, else anyone can use them to decrypt. But they are intrinsic to the code, complicated, and need to always work (the obvious exception is reflection which can be used to view even private methods in most cases, when SecurityManager is not configured to prevent this)

Creating an SDK for community consumption.

Here public takes on a wholly different meaning, since this is code that the whole world may see (not just internal to my application). We put code into private methods if we don’t want the SDK users to see it – we don’t see this as code smell, merely as how SDK programming works. But we need to test my private methods, and they are where the functionality of my SDK actually lives.

To test legacy code with large and quirky classes, it is often very helpful to be able to test the one private (or public) method

To test legacy code with large and quirky classes, it is often very helpful to be able to test the one private (or public) method.

We can use the junitx.util.PrivateAccessor package.

Java Code
import junitx.util.PrivateAccessor;

PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue);
PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class[] parameterTypes, java.lang.Object[] args);

In the Spring Framework we can test private methods using this method:

ReflectionTestUtils.invokeMethod()

For example:

ReflectionTestUtils.invokeMethod(TestClazz, “createTest”, “input data”);

Generic function to test private fields:

Java Code
protected <F> F getPrivateField(String fieldName, Object obj)
throws NoSuchFieldException, IllegalAccessException
{
Field field =obj.getClass().getDeclaredField(fieldName);

field.setAccessible(true);
return (F)field.get(obj);
}
[ad type=”banner”]

If using Spring, ReflectionTestUtils provides some tools that help out with minimal effort.

For example, to set up a mock on a private member without being forced to add an undesirable public setter:

ReflectionTestUtils.setField(theClass, “theUnsettableField”, theMockObject);

Using the Java reflection API, Two examples:

Calling methods, e.g. private void method(String s) – by Java reflection

Java Code
Method method = targetClass.getDeclaredMethod("method", String.class);
method.setAccessible(true);
return method.invoke(targetObject, "mystring");

Calling methods, e.g. private void method(String s) – by Picklock

Java Code
interface Accessible {
void method(String s);
}

...
Accessible a = ObjectAccess.unlock(targetObject).features(Accessible.class);
a.method("mystring");
[ad type=”banner”]

Setting fields, e.g. private BigInteger amount; – by Java reflection

Java Code
Field field = targetClass.getDeclaredField("amount");
field.setAccessible(true);
field.set(object, BigInteger.valueOf(42));

Setting fields, e.g. private BigInteger amount; – by Picklock

Java Code
interface Accessible {
void setAmount(BigInteger amount);
}

...
Accessible a = ObjectAccess.unlock(targetObject).features(Accessible.class);
a.setAmount(BigInteger.valueOf(42));

Categorized in: