How do I test a class that has private methods, fields or inner classes?
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
and private static
variables as well as invoke private
and 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);
Notes:
TargetClass.getDeclaredMethod(methodName, argClasses)
lets you look intoprivate
methods. The same thing applies forgetDeclaredField
.- The
setAccessible(true)
is required to play around with privates.
How do I test a class that has private methods, fields or inner classes?
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
and private static
variables as well as invoke private
and 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);
Notes:
TargetClass.getDeclaredMethod(methodName, argClasses)
lets you look intoprivate
methods. The same thing applies forgetDeclaredField
.- The
setAccessible(true)
is required to play around with privates.
Should I test private methods or only public ones?
I do not unit test private methods. A private method is an implementation detail that should be hidden to the users of the class. Testing private methods breaks encapsulation.
If I find that the private method is huge or complex or important enough to require its own tests, I just put it in another class and make it public there (Method Object). Then I can easily test the previously-private-but-now-public method that now lives on its own class.
Is it OK to make a private method to non-private just because to make it easier for testing?
I think this is something pretty personal. In most of the scenarios I don't see any harm on changing the scope of a method from private to protected/package private if this helps to write better unit tests. It not only allows to invoke the method from your test - which you might do either way using reflection -, but also to override/mock that method when testing another one invoking this.
However, if you don't want to do it you still can use tools like Spring's ReflectionTestUtils to make the invocation of private methods less painful.
How to use VisibleForTesting for pure JUnit tests
The Tag itself helps with the linter to identify unwanted access.
To lower the risk of use it directly, add this methods as internal
in Kotlin or protected
in Java instead of public
and with that only the tests or classes that are in the same package will be able to access that method.
Java:
@VisibleForTesting
protected Address address() {
return mAddress;
}
Kotlin:
@VisibleForTesting
internal fun address(): Address {
return address;
}
Unit testing of private methods
If the methods are complex enough to warrant testing in isolation, then refactor them into their own class(es) and test via their public interface(s). Then use them privately in the original class.
Related Topics
How to Set Java Max Heap Size for Running from a Jar File
How to Debug a Multi-Threaded App in Intellij
How to Pass Console Arguments to Application in Eclipse
Constructor Synchronization in Java
How to Change the Default Application Icon in Java
How Do Java Method Annotations Work in Conjunction with Method Overriding
Java Static Initialization Order
Null-Safe Mapping Comparator Using Default Implementations
Java Creating a New Objectinputstream Blocks
Difference Between Openjdk and Adoptium/Adoptopenjdk
How to Invalidate an User Session When He Logs Twice with the Same Credentials
Convert .Jar to an Osx Executable
Java Code for Getting Current Time
How to Convert Set<String> to String[]
How to Get Annotations of a Member Variable