Performance Zone is brought to you in partnership with:

Axel Fontaine is a software development expert and freelance consultant based in Munich. He is specialized in Continuous Delivery. He has extensive experience with the full software development lifecycle. He hates complexity with a passion. As an architect, developer, coach and consultant he helps his customers improve the way they develop and deliver software. To alleviate one of the traditional pain points, he started Flyway, the Agile Database Migration Framework for Java. He frequently speaks at Java User Groups. Axel is a DZone MVB and is not an employee of DZone and has posted 7 posts at DZone. You can read more from them at their website. View Full User Profile

Testing Private Methods in the Java World

07.17.2012
| 5964 views |
  • submit to reddit
Testing private methods is something that has traditionally drawn heated debates in the Java world.

The solutions usually fall into 4 categories:
  • Don't test private methods
  • Use reflection
  • Use a nested class
  • Change the visibility

Let's look at them in turn:
Don't test private methods
This really leaves us with three choices:
  • refactor to make the method public in some helper class
  • test through a calling method with a higher visibility
  • give up
A delightful choice between increased bloat, higher test complexity and resignation!
No, thank you!

Use reflection
Why make things simple when you can also make them hard and long-winded? Haven't you always been dreaming of needing 10 lines of code to make a method call? (Yes, there are now even entire tools dedicated to this big operation!) Extra bonus points because you can now also prevent your IDE's compiler and refactoring tools from helping you!
No, thank you!

Use a nested class
No too bad, but with 3 significant drawbacks:
  • no separate sources / test sources folders
  • larger classes
  • unit test code in production binaries
We can do better.

No thank you!

Change the visibility
This leaves us with the last option. Not perfect either, but by far the most pragmatic!
It trades a slight increase in visibility (to package-protected) for greatly simplified calling (a regular method call, no less!), while still preserving the valuable sources / test sources separation.
And with a simple documentation habit, it becomes clear to everyone why this design trade-off was made:
?
/* private -> testing */ void myMethodUnderTest() {
    ...
}
So the next time you face this problem, choose the pragmatic route. And enjoy a coffee while everyone else is still trying to complicate things. :-)
 
Published at DZone with permission of Axel Fontaine, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Gervais Blaise replied on Wed, 2012/07/18 - 2:05am

 

But private methods are.. private. They contains code who help the public method to work, they are related to the owning class only and thus they haven't to be tested...

The goal is to test that a class is doing what she is supposed to do without relying on how she do it. 

 

Christian Schli... replied on Wed, 2012/07/18 - 2:34am

Private property is private property and you need to keep out unless you are authorized to access it!

That being said, if you have a private method which is so complex that you feel it needs testing, then this is nothing but a code smell! The solution is to refactor it. Either reduce the complexity or make the method public. In conforming to SOLID principles, this might imply to spin off a new class to host this method.

Don't compromise your design for testing - never!

Barry Smith replied on Wed, 2012/07/18 - 5:36am

You should not be modifying your code purely for the benefit of your tests – your code should be completely ignorant of the existence of test cases. The only way to achieve this is by using reflection to override the private restriction and make the calls. Your objection seems to be that this takes some extra coding – well, so what? That’s the price you pay for doing it right. As you say, tools are appearing to help with this – that alone should give you a hint that the community is accepting this is the right way to go.

Misja Alma replied on Wed, 2012/07/18 - 6:31am

I don't see why you shouldn't modify your code purely for the benefit of your tests? The testability of your code is something to always keep in mind.

If you would be doing TDD, your code would even be well testable by default and your method would not have been private in the first place.

 I think making the method package private is the best solution. Just make sure that the package your class exists in contains only classes that are allowed to call your method and for all practical purposes your method is as private as it should be. 

 

Caspar MacRae replied on Wed, 2012/07/18 - 6:48am

 

Exactly what Misja said - your private methods would be exercised by unit tests invoking methods on the public API, at some point your private method must be called by a public one otherwise it's unused (so delete it - problem solved).

Unit tests act as the client of the (unit's) API under test - so we are necessarily testing the public interface.  If you have private methods that aren't covered by tests of the public interface then your design is almost certainly wrong.

The only time I need to manipulate a private/protected method/field is when mimicking dependency injection for component testing, and I have a simple test util static method for injecting these mocks.

You'd be better off changing the title to "How to test legacy code's private methods" or "How to do the complete opposite of TDD with limited success".

 

Barry Smith replied on Fri, 2012/07/20 - 7:53am

The testability of your code is something to always keep in mind.

Quite - in fact, if you need to test a private method in the first place it's probably quite a strong hint that you have an algorithm or process which should be extracted off into its own class (a la Fowler's 149 - Extract Class refactoring).

Calum Maclean replied on Fri, 2012/07/20 - 2:32pm

If you do decide to make your private methods more visible (package protected or public), it can be a good idea to define an annotation ("@IncreasedVisibilityForTestingPurposes"), so that you can annotate these methods.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.