It's Not About Testing Private Methods
I was able to attend RubyConf and truely enjoyed it. One of the best moments was a discussion that took place during Stuart Halloway’s Refactorum discussion. On the screen he displayed a piece of Rake that he wanted to refactor. With the blessing of Jim, who was sitting in the front row, Stu began the journey. He then showed the unit test that he used to test the private method he wanted to refactor. Unfortunately this is where the discussion got carried. I’ve seen posts by both Jay Fields and Jason Rudolph that talk about the how in testing private methods, and a lot of discussion around the blogsphere about how wrong this is.
Whether you agree with testing private methods or not, people are missing the subtlety of what Stu really did. Taken out of context I feel that the real message was missed.
Tightening the Feedback Loop
The first thing he did was identify a piece of code he wanted to refactor. The piece he found happend to be a private method. This method was fully tested (100% coverage), but it was tested through it’s public interface. If something in the private method was changed, it would have been picked up, but the unit tests were testing a level higher than the method that was being refactored. What Stu did (before performing any of the refactoring) was to tighten the feedback loop. He gave himself a safety net that was closer to the problem being tackled instead of relying on the one that was there. That way, if he broke something in the method he was refactoring, he would know right away instead of identifiying what was broken through a side effect.
Are Integration Tests Enough?
I also saw a suprising post from a highly regarded individual who said they don’t really unit test much. They rely on the integration and functional level tests to make sure that things are working. Yes this made the hair on the back of my neck standup. It goes against everything I believe in as a religious TDD’er. But after thinking it over for some time I realized that it’s all about the feedback level you are comfortable with. If something breaks I want to know about it at the most granular level possible. If you choose to only create functional level tests, and you are using a tool to check your covereage levels (such as rcov) you are still building that safety net, just further away from the actual code.
I know here at EdgeCase we rely on extremely tight feedback loops. We typically deliver projects in terms of weeks, not months, we work in weekly iterations and we test at the most granular of levels. We still rely on integration testing to ensure things work together, but when it comes to the code, the closer to the source, the better.


