If you've ever written any serious unit tests for your code then you'll know that testing private methods can be a bit tricky. The only class that has access to a private method is the class that defines it. So how are you supposed to test it from another class that doesn't have visibility of the method?
One solution would be to NOT declare it as private. This would work, but it's not much of a solution. Methods are made private for good reason and you can't just go around changing their access to suit your testing needs. That's just wrong.
Purists would say that you should test private methods via the public methods that expose their functionality. Purist say a lot of crap.
Seriously though, sometimes you need to test a private method, and there just no way around it. Fortunately there's easy solution to the problem. A bit of reflection should do the trick.
/**
* Invokes a private method on a class or object. This method
* can invoke static methods on classes, and instance methods
* on objects.
*
* When invoking an instance method, the instance of the object
* must be passed as the first parameter. For static methods,
* this parameter can be null.
*
* @param object the object to invoke the method on (this is
* only applicable for instance methods, can be null
* for static methods).
* @param clazz the class of object.
* @param methodName the name of the method to invoke.
* @param parameters parameters passed to the method.
* @return result from the method or null if method returns void.
*/
public static Object invokePrivateMethod(Object object,
Class clazz,
String methodName,
Object... parameters) {
// build an array of parameter types
Class[] params = new Class[parameters.length];
for (int i = 0; i < parameters.length; i++) {
params[i] = parameters[i].getClass();
}
Object result = null;
// try to execute the method
try {
Method method = clazz.getDeclaredMethod(methodName, params);
method.setAccessible(true);
// are we invoking a static method or an instance method?
if (object != null) {
result = method.invoke(object, parameters);
} else {
result = method.invoke(clazz, parameters);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
The javadoc comment pretty much explains it, but here's a quick example that you shows how to use it.
Let's assume we have a class called Greeter that looks like this.
public class Greeter {
// a private instance member
private String name;
// public constructor
public Greeter(String name) {
this.name = name;
}
// static method that responds with a cheery greeting
private static String sayHello(String name) {
return "Hello " + name;
}
// instance method that responds with a cheery greeting
private String sayHello() {
return "Hello " + this.name;
}
}
Notice it has two private methods. One is a static method, the other is an instance method. Using
invokePrivateMethod() that we defined earlier we can invoke these methods as follows.
// invoke a static method
invokePrivateMethod(null, Greeter.class, "sayHello", "Shane");
// invoke an instance method
Greeter greeter = new Greeter("Shane");
invokePrivateMethod(greeter, greeter.getClass(), "sayHello");
Now you really have no excuse for not writing unit tests ;)