Join any discussion about unit testing and there's one question that will invariably come up: how do you test private methods?
There are a number of answers. Some people advocate increased visibility. They say that if you feel that you must test a private method, it's really no great sin to make it protected, public or package private in order to make it testable.
Other people say that you can use special tools to access private methods. In Java, at least, you can quite easily rig something up with reflection to give you any kind of access you'd like.
These are "okay" answers, but really they are missing something. When I write tests and I have the urge to test a private method, I take it as a hint. The hint tells me that my class is encapsulating so much that it has ceased to be "understandable" by tests through its public interface. I listen to the hint, and factor my design differently. Usually, I end up moving the private method (and possibly some methods around it) to a new class where it can be non-private and accessible to tests.
Aiming for testability actually changes your design.
But, is that good?
The answer for me, so far, has been yes. There appears to be a synergy between testability (at the unit level) and good design. If you aim for testability and make some good choices, design gets better. If you aim for good design, your design becomes more testable.
In the end, it all comes down to cohesion and coupling. If classes are deeply coupled with their neighbors, it is hard to control them in a test or observe them independently. If a class isn't cohesive, it may have some logic which is not easily exercisable through its public interface.
It seems that reverse is true also. Classes which are hard to instantiate and use in a test harness are more coupled than they could be, and classes with private methods that you feel the urge to test, invariably have some sort of cohesion problem: they have more than one responsibility.
I suspect that some people reading this might think it is a load of wishful thinking, or that this synergy between testability and good design is just a hypothesis without much to back it. All I can say is that in the community of people doing test-driven development there are a number of people who have found that this question of testing private methods doesn't come up much in their practice. They target both testability and good design and find that both goals nurture each other.
Is the synergy real? I think it is. When a bit of functionality is not easily understood by a test at the public interface, the chances of it being easily understood by a human are ridiculously low. And, if there is any universal baseline for good design it has to be understandability.
So, having said all of this, I end this blog with a challenge: Can anyone come up with an example in which there is a private method that they feel that they have to test.. something that they don't feel comfortable testing through the public interface of the class, but which can't be made testable with a better design?
Right question. Wrong answer. Making the method testable by making it public is a mistake. Now you have a method you don't need in your API. Making the method testable by making it public in another public class is two mistakes. Now you have a method and a class you don't need in your API.
Private methods are implementation details that can and should change routinely at the convenience and whim of the programmer. Writing explicit tests for them locks down your design and makes it harder to refactor and optimize.
The right answer is to test the method through the public methods that call the private method. If you can't make the public method call the private method, then the private method is dead code and should be eliminated.
Posted by: Elliotte Rusty Harold | June 18, 2009 at 08:16 AM
One more thing, that may explain why we frequently disagree on this point. Looking through your other posts you seem to think that the worst possible thing is a bulky class. You're willing to bulk up the public API if it makes the individual classes smaller and more manageable. I'm not willing to make that tradeoff. I think a bulky API is much worse than a bulky class, and I will hide a lot of private complexity inside a class if it makes the public API of the entire system simpler.
Posted by: Elliotte Rusty Harold | June 18, 2009 at 08:24 AM
My favourite half-way house solution when I feel lazy is to add
boolean isPrivateMethodWorkingOk( expected params, test driver params )
{
results = callPrivateMethod ( test driver params );
boolean isOk = results agree with expected params ;
return isOk ;
}
You can see the actual coding varies a bit with language and access to result parameters.
It is half way because
- the poor coupling has not been addressed
- the private method stays private
- the test method is not as open to abuse as making the private method more visible
- it does mix code in for test with production code
I find it a useful quick and dirty hack sometimes.
Posted by: Al Mellor | June 18, 2009 at 08:53 AM
Hello Michael!
A friend working as speech therapist once told me that children learning two languages from start gets a "thicker language-trunk" allowing new language-branches to sprout more easy. This means these whiz-kids has easier to adopt new languages later. Perhaps because they avoid hard coupling to one language in the brain-signaling-substances? (Boy... realizing I'm far out on thin ice here :-)
If I have to access bizlogic from presentation layer AND from testcode then the bizlayer gets a thicker trunk. Definitely big synnergy effect.
I prefer introducing decoupling instead of tricks like subclassing because with subclassing I loose the synnergy effect. But then, that's me. Or is it because I read this article two years ago? I'm not sure! :-)
Regards,
Rasmus
Posted by: Rasmus Rasmussen | June 18, 2009 at 12:47 PM
Elliotte: I think we've been talking past each other. It might be better if we had code in front of us. I never want make private methods public to for testing. I do, however, enjoy moving them to new classes where they can be accessible to tests yet inaccessible through the original class's interface.
Posted by: Michael Feathers | June 18, 2009 at 04:54 PM
This is so contrary to my ood upbringing where everything is made private except for the logical operations that a consumer needs. I was also trained to break logic up into 'page' size methods, resulting in too many methods to expose through a public interface. Many of these functions are utility type functions and a person may argue that they should be put into a static utility class but often times there is business logic specific to the class that should reside inside the class but not be exposed.
With TDD at the forefront of every developer's mind, we need a non-invasive way of testing code easily. Using AOP for these purposes has certainly entered my mind on a number of occasions. Another notion for testing that I fantasize about is a highly configurable runtime that can provide state and behavior info on selected objects.
Posted by: Becky Breeden | June 12, 2011 at 07:12 AM