in TDD you are often confronted with the question “should I restrict my unit test to public methods or include private ones as well?”.
There isn’t a widely accepted consensus and there are many articles around on the subject. I’ve been thinking about it recently and this is my take on it.
A class’ public interface is a contract between the class and its users. When you test a class’ public interface you are trying to ensure that it respects the terms of the contract. So testing a public interface is technically enough to ensure that your program is correct (within the scope of unit testing of course, not in a general sense).
Generally nobody cares how your class is internally implemented as long as it works as advertised. Private members are an implementation detail and are used by public members anyways (otherwise you could just delete them), so tests on the public interface cover private members as well.
However, tests on private methods have a benefit: they can help you spot errors closer to where they are originated. You can see it this way: tests on public methods tell you that something went wrong, while tests on private methods can tell you where something went wrong. In other words they bring some comfort.
While additional comfort is nice to have, it always comes at a cost. These are the main costs you’ll assume when deciding to test private members:
- You’ll have to write more tests.
- Maintenance becomes quite stressful as you’ll be changing/adding/removing several tests every time you make a change in a class implementation.
- You miss the benefits of LDD (Laziness-Driven Development –invented by myself, don’t bother looking in wikipedia). In short, if a developer must write tests for public members only, she will keep them private unless really necessary, just because it takes less work. And keeping the public interface as narrow as possible is a good thing.
In order to answer the original question you’ll have to decide if the benefits are greater than the costs.
Personally, I only test public members and occasionally make an exception for private members that produce values difficult to verify at a glance.
When you combine the output of methods that produce “obvious values” it’s generally easy to spot what went wrong (a null reference, an incompletely initialized object, a wrongly formatted string, etc.). On the other hand, when methods generate for ex. floating point values, it’s difficult to quickly tell if something is wrong, thus it’s difficult to understand what caused a test to fail.
For example, I have a public GetPlexoidMass() function that computes the mass of a plexoid using a complex formula based on sine and cosine*. It made sense for me to test the private Sin and Cos functions as well, so that when a test for GetPlexoidMass turns red it takes me less time to figure out what caused the error without debugging every single step in the formula. The intermediate results inside GetPlexoidMass are floating point numbers and it’s otherwise difficult to understand which one is wrong without an accurate and time-consuming analysis.
This is a case you often find in number manipulation and/or mathematical-intensive libraries, usually found at an application’s core. This kind of function is harder to find the more you move towards the application surface. I would go as far as saying that feeling the constant need to test private members near the application surface may be a code smell and could indicate a problem in the application layering.
I hope these elements may help you make the right choice. If you have other criteria or considerations please let discuss in the comments!
* dummy example of course