Unit Test Private Methods in Java

December 13, 2010

Over the past few days I have been pondering how best to unit test a private method. I shouldn’t be testing private methods you shout? I agree: well engineered tests for your public contract should provide all the code coverage required. However, there are always corner cases to deal with. Recently I have come across such a case, and so I will put the controversy surrounding private method testing aside for the purpose of this post and investigate the best way to test private methods in Java.

One of the best overviews on the subject is an article by the esteemed Bill Venners. To quickly summarise, he concludes that the only four options you have if you want to test private methods are:

  1. Don’t test private methods.
  2. Give the methods package access.
  3. Use a static nested test class.
  4. Use reflection.

I like to avoid reflection whenever possible (am I the only person who feels like I have to take a shower after using it?), and I do not see why I would want to increase access visibility of the methods for the sake of testing. Instead, I am going to build on his idea of nesting a static class for testing within the production class.

Using a static nested class for testing is possible because it can access the private methods of its enclosing class. There are some disadvantages with this method, however. The static nested class contains test code, which could eventually find its way into a production environment. It means that your unit tests are no longer logically separated from production code, and it is likely the production code would have a dependency on JUnit for any level of reporting.

I propose a package visible inner class, which does nothing more than expose the private methods of its enclosing class the developer wishes to test. To create the class, do the following:

  1. Create an inner class with default (package) visibility
  2. For each private method to test, add a method to the inner class with default (package) access and an identical method signature as its private counter part.
  3. Have the new method call the private method

To test the private methods of a class, do the following:

  1. Create an instance of the inner class
  2. Call the methods you wish to test as if you were accessing the private methods directly

This is much better illustrated with an example:

public final MyClass {

    /**
     * <p>Exposes private methods for unit tests. This class must not be used
     * for any purpose other than unit testing.</p>
     */
    final class PrivateTests {

        /**
         * <p>Strictly for unit testing only.</p>
         *
         * <p>See {@link MyClass#myPrivateMethod(String)}</p>
         */
        String myPrivateMethod(final String param) {

            return MyClass.this.myPrivateMethod(arg);
        }

    }

    private String myPrivateMethod(String arg) {
        // Code to test
    }

}

The inner class PrivateTests can now be used in unit tests to access private methods of MyClass directly:

public final class MyClassTest extends TestCase {
	public void testMyPrivateMethod() {
		PrivateTests privateTests = new MyClass().new PrivateTests();
		assertEquals("expected", privateTests.myPrivateMethod("param"));
	}
}

Here is a list of advantages of this method over the many proposed solutions (not just Bill Venners’ solutions) I came across while researching this subject:

  • The visibility of the private method is not compromised
  • The class MyClass can be marked final
  • The developer can control which private methods are exposed for unit testing
  • The solution is strongly typed, and will work with all IDE re-factoring tools
  • No JUnit dependencies are introduced into the production code
  • Testing code and production code is still logically separate
  • No runtime performance or memory penalty
  • The inaccessible inner class will not appear in the IDE intellisense
  • You avoid (yucky) reflection!

The inner class is not referenced by production code and will be removed without any nasty side effects by a shrinker (like the excellent Proguard). If you do not happen to use a shrinker it is worth noting that the inner class will be harmlessly, but redundantly, included in your deployment JAR.

I hope this approach is of some use, and as always feedback is appreciated and encouraged.

tags: , , ,
posted in Development by admin

Follow comments via the RSS Feed | Leave a comment | Trackback URL

3 Comments to "Unit Test Private Methods in Java"

  1. Gabriele wrote:

    With dp4j reflection doesn’t have to be that disgusting and you can preserve your production code from modification for testing!
    All you have to do is add dp4j.jar to your path and use JUnit’s @Test annotation (and access the private methods and fields as if they were public).

    @see http://www.junit.org/node/591

    P.S. agreed that reflection is otherwise disgusting.

  2. Radegast wrote:

    dp4j does not work perfectly with Eclipse. So, Idea with inner classes seems useful. But i think, extension for eclipse that generate wrap public methods will be better.

  3. http://tinyurl.com/creaemery09734 wrote:

    Exactly how long did it require u to compose “Unit Test Private Methods in Java | >/dev/null”?
    It provides quite a lot of really good information and facts.
    Thank you -Wilbur

Leave Your Comment

 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org