Unit Testing only public methods is bad 1
I think I’ve had the argument about testing only the public interface for a class multiple times now, probably at multiple jobs, and I’ve never really gotten a good answer about it. My point of view is that only testing the public interface is the wrong way to go about unit testing.
The way I see it, unit testing should test “units”, and in the case of software that translates in my head to “units of work”. Public interface methods are not “unit of work” from the point of view of the person writing or maintaining the software (the person writing the unit tests). Public interface methods may the “units of work” for a QA tester or an integration tester, but they are not for the author of the code.
From experience, taking the approach of testing the public interface for a class often leads to very difficult to maintain unit tests. Very often, public interface methods will utilize several logic branches and several “helper” methods that are often private or protected. They can often deal with complex and deeply nested datastructures. These factors can lead to unit tests can become very difficult to set up, give a false sense of coverage because they don’t exercise all logical paths, or are hard to maintain because the setup is so unwieldy.
The alternative is breaking your code up into the most atomic units that make sense and then testing these individually. This means testing all of the private and protected methods and not just the public interface. The difficulty in this arises when trying to determine how to write the tests for your public methods. The public methods still accomplish the same data processing regardless of how you refactor your code or write your tests for the “helper” methods, and testing the smaller methods doesn’t remove logical complexity from the system as a whole.
At this point in time, the only thing I can think of is the suggestion to make sure that no single method is responsible for too much decision making. Maybe the best practice is to attempt to have a system where a single method tries to only use a single layer of a datastructure to make it’s decision, and leaves other decisions to other methods. This way you can construct a test for a method by only providing a single layer of the datastructure, which should hopefully limit the amount to setup you need to do. I’m still working on this.
HI,
I have been unit-testing the TDD way for some years now. There was a time when I asked myself “If I am supposed to test everything, how am I going to test private methods?” The answers I found were :
Now my programming style as evolved, and things have changed. The classes I am writing are small. I hardly write private methods. All the “helping logic” always (as far as I remember) finds its way to a new class, according to the SRP (Single Responsibility Principle), and the class will be tested. I can hardly remember writing private methods recently.
Now, should we worry about making things private? My opinion (but it’s only mine) is no. If you want to prevent people from using private parts of the code you are writing, you can’t.They still have the freedom to come and make it public. I prefer finding a way to write a useful public class instead of a useful private method.