How do I use JUnit to test a class that has internal private methods, fields or nested classes?
It seems bad to change the access modifier for a method just to be able to run a test.
If you have somewhat of a legacy Java application, and you’re not allowed to change the visibility of your methods, the best way to test private methods is to use reflection.
Internally we’re using helpers to get/set
private static variables as well as invoke
private static methods. The following patterns will let you do pretty much anything related to the private methods and fields. Of course, you can’t change
private static final variables through reflection.
Method method = TargetClass.getDeclaredMethod(methodName, argClasses); method.setAccessible(true); return method.invoke(targetObject, argObjects);
And for fields:
Field field = TargetClass.getDeclaredField(fieldName); field.setAccessible(true); field.set(object, value);
TargetClass.getDeclaredMethod(methodName, argClasses)lets you look into
privatemethods. The same thing applies for
setAccessible(true)is required to play around with privates.
The best way to test a private method is via another public method. If this cannot be done, then one of the following conditions is true:
- The private method is dead code
- There is a design smell near the class that you are testing
- The method that you are trying to test should not be private
When I have private methods in a class that are sufficiently complicated that I feel the need to test the private methods directly, that is a code smell: my class is too complicated.
My usual approach to addressing such issues is to tease out a new class that contains the interesting bits. Often, this method and the fields it interacts with, and maybe another method or two can be extracted in to a new class.
The new class exposes these methods as ‘public’, so they’re accessible for unit testing. The new and old classes are now both simpler than the original class, which is great for me (I need to keep things simple, or I get lost!).
Note that I’m not suggesting that people create classes without using their brain! The point here is to use the forces of unit testing to help you find good new classes.