Approach 1: Don't Test Private Methods

As I mentioned in the introduction, I first heard the advice to suppress my
occasional urges to test private methods from Daniel Steinberg. But Daniel is
not only source of this advice that I have encountered. It seems to be a
common attitude in the Java community. For example, the JUnit FAQ [4]
states:

Testing private methods may be an indication that those methods should be
moved into another class to promote reusability.

If you have a thorough suite of tests for a class's exposed (non-private)
interface, those tests should, by their nature, verify that any private method
within the class also works. If this isn't the case, or if you have a private
method so complex that it needs to be tested out of the context of its public
callers, I would consider that a code-smell.

And Dave Thomas and Andy Hunt, in their book Pragmatic Unit
Testing [6], write:

In general, you don't want to break any encapsulation for the sake of testing
(or as Mom used to say, "don't expose your privates!"). Most of the time, you
should be able to test a class by exercising its public methods. If there is
significant functionality that is hidden behind private or protected access, that
might be a warning sign that there's another class in there struggling to get
out.

I believe all this advice. Most of the time, private methods can be most
effectively tested via approach 1, indirectly by testing the package-level,
protected, and public methods that call them. But inevitably, some people in
some situations will feel that directly testing a private method is the right
thing to do.

In my case, I tend to create many private utility methods. These utility
methods often do nothing with instance data, they just operate on the passed
parameters and return a result. I create such methods to make the calling
method easier to understand. It is a way to manage the complexity of the
implementation of the class. Now, if I extract the private method out of a
method that already works and has good unit test coverage, then those
existing unit tests will likely suffice. I needn't write more unit tests just for
the private method. But if I want to write the private method before its
calling method, and I want to write the unit tests before writing the private
method, I'm back to wanting to directly test the private method. In the case
of private utility methods, I don't feel my urge to directly test the methods is,
as the JUnit FAQ put it, "an indication that those methods should be moved
into another class to promote reusability." These methods are really only
needed in the class in which they reside, and in fact are often only called by
one other method.

Another reason I sometimes feel the urge to test private methods
directly is that I tend to think of unit testing as helping me achieve a robust
system by building that system out of robust parts. Each part is a "unit" for
which I can write "unit tests." The unit tests help me ensure each unit is
functioning correctly, which in turn helps me build a system that functions
correctly as a whole. The primary unit I think in terms of when programming
in Java is the class. I build systems out of classes, and unit tests give me
confidence that my classes are robust. But to some extent I also feel the
same way about the private methods out of which I compose package-access,
protected, and public methods. These private methods are units that can be
tested individually. Such unit tests give me confidence that the private
methods are working correctly, which helps me build package-access,
protected, and public methods that are robust.

Approach 2: Give the Methods Package Access

As I mentioned in the introduction, giving methods package access was my first
approach to testing private methods with JUnit. This approach actually works
just fine, but it does come with a slight cost. When I see a private access
specifier on a method, it tells me something I like to know—that this
is part of the implementation of the class. I know I can ignore the method if
I am just trying to use the class from another class in the package. I could
figure this out about a package-access method by looking more closely at
the name, documentation, and code
of the method, but the word private communicates this far more efficiently.
Moreover, the main problem I have with this approach is philosophical.
Although I don't mind "breaking encapsulation for the sake of testing," as
Dave and Andy would put it, I just don't feel good about breaking
encapsulation in a way that changes the package-level API. In other words, although I
am quite enthusiastic to test non-public methods of classes, i.e., to create
"white-box" unit tests, I'd rather the API of the classes under test, including
the package-level API, not be changed to facilitate those tests.

Approach 3: Use a Nested Test Class

A third approach to testing private methods is to nest a static test class
inside the production class being tested. Given that a nested class has access
to the private members of its enclosing class, it would be able to invoke the
private methods directly. The static class itself could be package access,
allowing it to be loaded as part of the white box test.

The downside to this approach is that if you don't want the nested test class
being accessible in your deployment JAR file, you have to do a bit of extra
work to extract it. Also, some people may not like having test code mixed in
the same file as production code, though others may prefer that approach.

Approach 4: Use Reflection

The fourth approach to testing private methods was suggested to me by
Vladimir R. Bossicard, who wrote JUnit Addons [7]. One day over lunch, Vladimir enlightened me that
the java.lang.reflect API included methods that allowed client
code to circumvent access protection mechanism of the Java virtual machine.
He also told me that his JUnit Addons project included a class,
junitx.util.PrivateAccessor [8], to assist in using the reflection
API for just this purpose: to write unit tests that manipulate private members
of the classes under test. The JUnit FAQ points to a similar class, called
PrivilegedAccessor [9], written by Charlie Hubbard and Prashant
Dhotke.

One advantage of using the reflection approach to testing private methods
is that it provides a clean
separation of test code and production code. The tests need not be nested
inside the class under test, as in approach 3. Rather, they can be placed
alongside the other tests that exercise the package-level and public methods
of the class. In addition, you need not alter the API of the class under test.
Unlike approach 2, private methods can remain private. Unlike approach 3, you
need not add any extra nested class at package access level. The main
disadvantage of this approach is that the test code is far more verbose
because it uses the reflection API. In addition, refactoring IDEs such
as Eclipse and IntelliJ usually aren't as adept at changing the names of
methods where they are referred to as Strings passed to the methods of the
reflection API. So if you change the name of the private method with your
refactoring IDE, you may still have to make some changes by hand in the
test code.