Only ever test your objects' public API
It was a real revelation to me when my mate, fellow programmer, and one-time ruby-mentor, Brian Guthrie @bguthrie gave me this piece of advice.
I'd just arrived in Melbourne, had just started 'taking my craft seriously' and was at the 2011 Melbourne Corey Haines' Code Retreat - which Brian was facilitating.
As an aside; if you haven't attended one, I'd highly recommend trying it out. It's a great environment to practice the art of arranging code with really smart people and no external pressures.
The instant I heard it, I knew it to be true. It's something so obvious that I knew I should have been able to articulate - but had never put into words, or coherent thought.
Why?
You object's reason to exist (its responsibility) is exposed by the messages it can accept. Assuming your runtime code only exercises its public methods, your tests should be able to find all edges by doing the same.
When implementation details are hidden, tests are much less brittle/fragile. You are free to refactor private implementation as much as you like without having to go and change your test (after all, why should you? The outcome is what you're specifying in test and it remains the same).
If your public API doesn't exercise all of the edges in your private implementation, you certainly have redundant code.
What makes this guideline really timeless, is the reciprocal cordiality it has with a number of other good practices. The Whys above hint that:
- Thought went into the responsibility (singular!) of the object
- Some code is merely implementation detail, and therefore uninteresting to the outside world
- Focusing on outcomes makes for more robust tests
- The messages in an OO system are what's really interesting
I'd love to hear other peoples' experiences with this guideline. By all means, if someone has an example of where it's necessary to test their objects' private methods, I'd love to hear them.
kthxbi, Stu