The Confession of a Test-First Traditionalist
I am not sure what David Heinemeier Hansson meant when he used the words "test-first fundamentalism", and "traditional unit test" in his controversial article TDD is dead. Long live testing., but I test-drive my code every day and follow the practice religiously, so I figured he may be talking about me. David, like many others, has struggled to test-drive his code, and took his frustrations out on unit tests, mocks, and architecture decisions he disagreed with. I can relate to that. In the second year of my three-year tenure with 8th Light, Inc, the company founded by Micah Martin and Paul Pagel, the son and apprentice of Uncle Bob Martin, respectively, I too had the same concerns. I brought them up to my coworkers, and contrary to popular belief, I was not prosecuted by the test-first traditionalist camp and my heart was not sacrificed to the god of test-driven development. Instead, we had a long and healthy debate over the internal mailing list, and in the end, I learned to use mock more carefully and deliberately. At the core of test-first traditionalism, our objective is not to convert you to our camp. We want to help you get better at what you do. We want to raise the bar for our profession. And in the spirit of that, here is what I learned about mocks. Don't Mock What You Don't Own Is a rule taken from the book Growing Object Oriented Software, Guided by Tests, and is blogged by Eric Smith. Mock is based on assumptions. We assume mock objects will behave the same way as their real counterparts under the circumstances we test in, but we could be wrong. And that's when mocking becomes a liability and creates a false sense of safety. If you have to make assumptions about code, at least make them about the code that you wrote, where you know the deficiencies of the implementation. Design vs Refactoring Mock is often used as a design tool to tease out interactions between the collaborators in your object. It focuses your attention on the interfaces of your objects rather than their states. However, this can also lead to coupling tests with implementations, and therefore make refactoring difficult. On the other hand, state-based testing only verifies the final state of the code, and thus makes changing implementation and refactoring easier. This article by Paul Gross was a good introduction to the philosophy of state-based approach for me. Mockist vs Classicist As a test-first traditionalist, I face the question of to mock or not to mock on a daily basis. Mock is a powerful tool for isolating objects and identifying dependencies. It is especially useful for working with legacy code - when I just want to cut out a clear path in a jungle of mess. Some days I go with mocks to drive the interactions of my code, and others, I fall back on the classicist approach of state-based testing to free my mind of hardcoded implementation details. YMMV.










