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

How To Unit Test Private Methods

Roger Keays is an artist, an engineer, and a student of life. He has no fixed address and has left footprints on 40-something different countries around the world. Roger is addicted to surfing. His other interests are music, psychology, languages, the proper use of semicolons, and finding good food.

Leave a Comment

Please visit https://rogerkeays.com/how-to-unit-test-private-methods to add your comments.

Comment posted by: Guus Bloemsma, 11 years ago

 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.

Comment posted by: , 11 years ago

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: Tomek Kaczanowski, 11 years ago

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: , 11 years ago

Executable examples. That's pure genius.

Comment posted by: Drew, 11 years ago

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: , 11 years ago

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: Vlad, 11 years ago

 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