How To Unit Test Private Methods

By , 19 September 2012

How To Unit Test Private Methods
How To Unit Test Private Methods

I've discovered that one reason I don't write as many unit tests as I should is because they live in a separate source tree, out of sight and out of mind. So I've moved my unit tests to be inner classes on the classes they test. A side effect of this is you can easily test the private methods of a class since the inner class has direct access to these methods.

Here is the configuration you will need to do this. Note, I am using TestNG, but it should be pretty similar in JUnit.

How To Unit Test Private Methods

By default surefire will not execute tests in inner classes so first you need to fix this and also tell maven where your test code is by adding this to your <plugins> section:

    <!-- unit tests live inside the java source files themselves -->
    <plugin>
      <artifactId>maven-surefire-plugin</artifactId>
      <version>2.12</version>
      <configuration>
        <testSourceDirectory>src/main</testSourceDirectory>
        <testClassesDirectory>target/classes</testClassesDirectory>
        <excludes><exclude>[none]</exclude></excludes>
      </configuration>
    </plugin>

Note that [none] is not a special keyword, it only exists to match no class files. You can put whatever rubbish in there (but a blank entry has no effect).

Your unit tests must be public static inner classes annotated with @Test, like this:

    @Test
    public static class UserEditorTest {
        public void test_private_method() {
           assertEquals(new UserEditor().somePrivateMethod(), "success");
        }
    }

Since the test class is an inner class, it can call the private method.

To run the test from maven, I use a wildcard on the test name so I don't have to specify OuterClass$InnerClass.

    $ mvn test -Dtest=*UserEditorTest

To get Netbeans to run the tests, you can use a wildcard so it finds the inner class. Go to the project properties and look for the Actions settings. You will need to set the parameters like this:

    -Dtest=*{className}

You can also run from a normal testng.xml test suite like this:

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite1" verbose="1">
  <test name="MyTest" >
    <classes>
       <class name="com.example.Example$ExampleTest"/>
    </classes>
  </test>
</suite>

This setup has improved my productivity and (more importantly) the coverage of my unit tests. Do you think using inner classes for unit testing is a bad idea? Let me know why in the comments below.

 

About Roger Keays

Roger is an active member of the JSF 2 Expert Group and is happy to be a contributor to the Java Community. He has been writing software since the age of 8 and his other interests include languages, science, travel and surfing.

Comment posted by: Vlad, last year

 Hi!

Do you have any way to filter out the test classes from the deliverable jar? Leaving them there means a lot larger archives.

regards, Vlad

Comment posted by: , last year

Hi Vlad,

You can do that by just removing the class files that match *$*Test.class. Something like this in shell:

$ rm `find target -name "*$*Test.class"`

But I actually like the fact that my code is shipped / deployed with all my tests. They only take up a fraction of the space of all my bundled libraries and you never know when they might come in handy.

Comment posted by: Drew, last year

One of my favourite examples of keeping the unit tests near the tested code is Python's doctest. You essentially have examples of calling the function in the function comments and doctest will run them to make sure they're valid!

Comment posted by: , last year

Executable examples. That's pure genius.

Comment posted by: Tomek Kaczanowski, last year

I have to say I'm surprised that you see a problem with test kept in parallel source tree. Current IDEs let you navigate easily from production code to tests (provided that you stick to the most popular naming pattern of test classes).

The price you have to pay - mixing test code with production - is not acceptable for me.

Comment posted by: , last year

Whatever works best for you of course... I'm hooked on embedding tests everywhere now. Even in shell scripts and config files. I also see shipping tests as an advantage. It's like opening the hood of your car and having a description of what each component is supposed to do and how to test it. I once had a hot water system like that and it saved me a cold shower or ten.

Comment posted by: Guus Bloemsma, last year

 Another advantage of using inner classes is having access to private members. This way you can avoid making members non-private just to test them.

Inner classes used to be the default way of testing in NetBeans. Unfortunately conventions are different now.

Add a comment

Please visit http://www.NinthAvenue.com.au/how-to-unit-test-private-methods to add your comments.

Join The Mailing List

Subscribe to our mailing list for the latest news and announcements.

Follow Ninth Avenue

Get Results With Women

Website Updates