Your Unit Tests Should Mind Their Own Business
One of the most common questions people ask is whether to unit test private methods. I struggle to find any reasons why we should, but I do know a lot of reasons why we should not. I'm not saying that there's never a reason to unit test private methods, I'm just saying to make sure you understand what that reason is before you go to all the effort.
In my opinion, the best way to achieve our unit test objectives is by validating our class's interfaces. And when I think about interfaces, I'm thinking about the public methods we expose to other modules in our application. If we can validate that each of these methods is behaving as expected, then I'm going to feel satisfied that the class works correctly. For the purposes of unit testing, I don't really care how the method achieves the result, as long as it's the right one. I don't care if the method figures out the result in-line, or by calling external methods or through internal private methods. If I call calculator.add( 2, 2 ) and get 4 then I'm happy. If I get 5, there's a problem.
In fact, if we're being good developers and remembering to re-factor our code as the application evolves, then there's a good chance that the method we use to determine that result is going to change over the application's lifetime. That gets back to reason #4 for having unit tests - they provide a safety net to ensure that our modules continue to function as we make changes to them. If those unit tests are dependent on how we provide results, then it means that every time we decide to change our class's inner workings, we have to update our unit tests. And if we have to rewrite our unit tests, then what is happening to our safety net?
"being able to quickly create, move around, and change the functionality of private methods is vital to remaining agile" -- Charles Miller, The Fishbowl
Okay, sure if we change our public interfaces, we have to update our unit tests. But that makes sense. It means our interface specifications have changed and so our tests better be updated accordingly. Changing our public interfaces should incur a significant cost because other code relies on them. In fact, one might even argue that having high costs (such as having to update our unit tests) provides a good reminder to us that it's in our best interest to keep our public interfaces stable.
On the other hand, the private parts of our implementations - those details that have been hidden behind our class's interface - should not be costly to change. If we give them the high cost of having to redo our unit tests then it puts up a barrier against refactoring that we really don't want. If we find that we're using the same logic in 3 different places in our class, we should be able to easily move that logic into a single private method and then simply re-run our unit tests as they already exist to make sure our class continues to function as expected. We shouldn't have to go write another unit test at this point because we haven't added any new functionality. We've simply refactored our existing code to be more maintainable.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)