Testing Private Methods

Recently I got asked by two of my developers about what to do with testing private methods. They explained they wanted to test some of their private methods that contain logic. The options they were considering included:

  • Making the private methods public.
  • Extracting out the methods into new classes.

As a pragmatic approach, both seemed reasonable, but I remembered reading multiple bits of advice on only testing the public interface of a class. Testing private methods is wrong and dangerous.

Simon Harris makes the common argument that you shouldn’t test private methods:

Now, I almost never test private methods. I say almost, just in case i’ve either done it once before and forgotten or I need to change my mind at some point in the future. But as far as I’m aware, I never test private methods.

I know I’ve wanted to test private methods before. I like to keep most of my public java methods around 10 lines or so if possible, so I’m constantly extracting out well defined private methods. Some of these contain conditional logic I’d like to test as a single unit, but I have to suffice testing the conditionals through the public method that calls them.

Hunting around for about 30 minutes turned up some insights on this issue.

Bill Venners defines four possible approaches to unit testing private methods:

  • Don’t test private methods.
  • Give the methods package access.
  • Use a nested test class.
  • Use reflection.

He does a good job of exploring each one, but his ultimate conclusion is that usually you shouldn’t test private methods, but if you need to any of the last three approaches will work.

Cedric Beust of TestNG fame has a stronger opinion:

My answer to the question “Should you test private methods” is a resounding YES!
When it comes down to testing, I follow a very simple rule: “if it can break, test it”.

Bruce Eckel agrees with Bill Venners that you should probably go ahead and test private methods if it makes sense:

I’m with Bill on private method testing. Unit testing allows you to test at the granularity of the method, and the reason you break code up into private methods is to manage complexity. But if you can’t test at that level, it’s defeating.

JB Rainsberger even has a recipe for testing private methods:

Recipe 17.6 Test a private method if you must

“You have a private method that is complex enough to warrant its own tests, but nevertheless is not important enough to promote to the public interface or refactor to a collaborating class. You could test the method indirectly through the public methods that invoke it, but you would rather test it in isolation, which is a laudable goal.

What’s so bad about testing private methods, anyway? Perhaps the greatest problem is that private methods are private for a reason: the author intended for nothing but this one class to have any knowledge of the particulars of its implementation. … In that sense private methods support refactoring very well by providing the design with a degree of freedom of change.

Junit Recipes

The Pragmatics also lean towards testing private methods if you have to:

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. When push comes to shove, however, it’s probably better to break encapsulation with working tested code that it is to have a good encapsulation of untested, non-working code.

Pragmatic Unit Testing

Bob Lee argues that package level scope should be used for testing:

Package scoping particularly shines during unit testing. Some programmers argue that you should only test through the public API. Don’t be silly. Limiting your tests to the public API contradicts the spirit of unit testing and subjects you to unnecessary dependency pain. I prefer to isolate and limit the amount of code I test at one time, and test as close to the code as possible.

Conclusion

So lots of thoughts, lots of options, but what to do? My conclusions are:

  • Try to avoid testing
    1
    private

    methods.

  • When you do need to test a
    1
    private

    method because it has enough logic to warrant unit testing just switch it to package scoping from

    1
    private

    .

2 comments to Testing Private Methods

  • Hi,

    I agree with Cedric that if it can break, test it. My argument isn’t against testing, it’s against testing private behaviour. I believe that if something is to be independently testable then it ought to be public and, if it doesn;t make sense to make it public on the existing class, factor the code into a separate, independently testable, class. I blogged about how I found taking such an approach really did a lot of good for my overall design: http://www.redhillconsulting.com.au/blogs/simon/archives/000288.html

    Cheers,

    Simon

  • I think there’s a lot of value to that approach, but as we ease into real TDD and much of the team gets adjusted to OO thinking I think these items will become more of an edge case.

    I’ll have to try out some of the design constraints you talked about like the no

    1
    if

    idea, nice.