Don’t test private methods
A common question when it comes to unit testing is:
How do I test private methods?
There are in fact a number of possible ways to do this.
- Create focused tests for public methods which are customized to exercise the private method we’re interested in, even though it is hard and creates difficult-to-understand tests.
- Use a tool that allows you to test private methods, such as PowerMock or Java’s reflection API, even though your tests become tightly coupled to the implementation.
- Increase the visibility to
default
orprotected
and call it from a normal unit test in the same package or through a subclass, even though you expose the class’ internal workings.
As you might imagine from the descriptions above, I believe that these strategies in most cases are wrong (even though they all work and could be useful once in a blue moon).
You get less maintainable code #
Testing should generally test behavior rather than implementation – what the result is rather than how it is done. A private method is by definition an implementation detail. It should be up to the implementor to rearrange the internals of the class in any way she sees fit, including having as many or few private methods as she wants. Therefore, we should not have a test which looks into the implementation and makes the existence of a private method into a requirement.
Doing this not only violates the privacy of the object under test, it also couples the test more tightly with the implementation. This leads to more brittle tests and code which is harder to refactor. All in all, testing private methods is unnecessarily invasive and leads to less maintainable code.
It should be noted that “white box testing” (writing tests with the knowledge of how the code under tests works internally) does not mean that you must tightly couple your tests to the implementation. It just means that you can write clever tests which will precisely target critical points in the implementation code. You can (and should) still write your tests in terms of behavior.
An opportunity to improve the design #
When you feel the need to test a private method, don’t ask “How do I test private methods?” Instead, ask “Why do I need to test this private method?” In many cases, wanting to test a private method indicates a design fault − a violation of the Single Responsibility Principle. The tests are often trying to tell you that the class under test is doing work enough for two. That the private method is complex enough to be worthy of a separate class.
The need to test a private method often indicates a new class waiting to get out.
My suggestion when you feel the need to test a private method is therefore to see if you can move the private method out of the current class in a way that not only makes it testable, but also improves the design.
The simplest way to do this is often to move the private method to a new class, along with any other private methods it uses, and make it public. Then make the original code use this new class to make the work of the private method. The image below illustrates such a case.
In some cases we don’t need to create a new class. Instead, we can sometimes make the private method into a public method on one of the classes it takes as arguments, especially if the method in question is static.
To summarize, if you have a hard time figuring out how to test some code (e.g. because it is private), it often means that the design is wrong. Fix the design issue rather than using brute force to test.
Updates #
- 2024-04-24: Republished this post which was originally written for my previous blog.