Should We Directly Unit-Test Private Functions?
Software developers have long debated whether to unit-test private functions (or private methods in object-oriented programming). This article will delve into the reasoning behind the undesirability and unnecessary nature of directly testing private methods. By understanding the principles of unit testing and the relationship between public and private methods, we can adopt a more effective approach to ensure the reliability and maintainability of our codebase.
- Undesirability of Testing Private Functions: Unit tests should primarily focus on testing behaviour rather than delving into the implementation details. In object-oriented programming, private methods are intentionally inaccessible from outside the class. Consequently, directly unit testing private methods opposes the intentions of encapsulation and probing the internal workings of logic not meant to be exposed.
- The Impact of Refactoring on Tests: Consider a scenario where a class has unit tests for both public and private methods. If we were to refactor the implementation significantly, the externally visible behaviour of the public methods should remain unchanged. However, such a refactoring may completely rearrange the internal workings of the class, rendering existing unit tests for private helper methods ineffective and broken.
- Viewing the Module as a Black Box: To gain a clearer perspective, let’s envision the class as a black box with a defined set of behaviours. We want to design our unit tests to validate those demonstrable behaviours without lifting the lid off the black box. By directly testing private helpers, we reveal the internal workings of the class, which can lead to mismatches between the tests and any changes made to the internals.
- Unnecessary Nature of Unit Testing Private Helpers: What a class does should be primarily unit tested through its public methods; that’s how it exposes its behaviour to external callers. While private helper methods contribute to the overall workings of a class, they are ultimately accessible indirectly via the public methods. By the same reasoning, private helpers not called by the exposed public methods serve no functional purpose and can be safely removed. By focusing on unit-testing the public interface, we ensure comprehensive test coverage of a module’s behaviour.
Conclusion
In light of the above reasoning, avoiding direct unit testing of private methods is advisable. Instead, we should adopt an approach that emphasises indirect validation solely through public methods. By adhering to this practice, we can maintain clean code thoroughly tested for its intended behaviour. Let’s keep in mind that private methods are intentionally hidden from external callers, while the public interface serves as the outward access point. As such, let’s prioritise testing through our public methods and direct our unit testing efforts accordingly.
Leave a Reply
Want to join the discussion?Feel free to contribute!