When dealing with this issue, there are two main approaches commonly used. The first is to test the method through another public method that calls it. The other would be to expose it publicly even if the only thing that needs access to it are the unit tests. Neither strategy is perfect or ideal but here are a couple of things to consider when choosing which is best for you.
Start off by considering your objective. My objective is to be able to make changes to the code-base with confidence. Additionally, if an issue presents itself, I want to be able to find and address the issue quickly.
When you have several private methods chained together, it becomes no different to test than one big super method. If there’s a problem with the logic, it can be cumbersome to track down the issue. On the flip side of that, if every method were public, you could test each method and ensure that it’s doing its little bit of work correctly. All of the methods doing their one job adds up to a complete workflow. If one of the methods fails to do its job, it’s quick and easy to identify where the issue lies. The drawback is that we totally destroyed the notion of a public vs. private methods and all the good things that come along with it.
One approach that I’ve taken with several companies is a hybrid. I will follow a classic module pattern and expose publicly only those methods that are called externally from outside the class. Then I create a ‘testObject’ and expose it publicly. The properties of my testObject are all the private methods that I otherwise would not be able to test. Now all my private methods are exposed publicly. While it’s not nearly as safe as keeping them private, at least I know that I should only ever see ‘class.testOject.somePrivateMethod’ being called from within my unit tests. If I ever do a code review and see someone calling ‘class.testObject.*’ in the core code, I know someone is calling the private method in a way it’s not intended.
It’s a great pattern and has worked very well for several enterprise implementations. It’s not perfect but is a good compromise in most cases. You’ll want to consider your application and the pros and cons of the various strategies before deciding which is best for you.