“I don’t use a knife when I eat, if need one it means the food hasn’t been cut up enough.”
“Forks are unnecessary, I can do everything I want with a pointed knife.” [1]
One of the things we realised when writing Growing Object-Oriented Software, is that the arguments about mocks in principle are often meaningless. Some of us think about objects in terms of Alan Kay’s emphasis on message passing, others don’t. In my world, I’m interested in the protocols of how objects communicate, not what’s inside them, so testing based on interactions is a natural fit. If that’s not the kind of structure you’re working with right now, then testing with mocks is probably not the right technique.
This post was triggered by Arlo Belshee’s on The No Mocks Book. I think he has a really good point, buried in some weaker arguments (the developers I work with don’t use mocks just to minimise design churn, they’re as ruthless as anyone when it comes to fixing structure). His valuable point is that it’s a really good idea to try setting yourself style constraints to re-examine old habits, as in this object-oriented calisthenics exercise. As I once wrote, Test-Driven Development itself can have this property of forcing a developer to stop and think about what’s really needed rather than pushing ahead with an implementation.
As for Arlo’s example, I don’t think I can provide a “better” solution without knowing more detail. As he points out in the comments, this is legacy code, so it’s harder to use mocks for interface discovery. I think Arlo’s partner is right that the ProjectFile.LoadFrom is problematic. For me the confusion is likely to be the combination of reading bytes from a disk and the construction of a domain structure, I’d expect better structure if I separated them. In practice, what I’d probably do is some “annealing” by inlining code and looking for a better partition. Finally, it would be great if Arlo could finish up the reworking, I can believe that he has a much better solution in mind but I’m struggling with the value of this step.
There is one more thing we agree on, the idea of building a top-level language that makes sense in the domain. Calling methods on the same object, like a Smalltalk cascade, is one way, although there’s nothing in the type to reveal the protocol—how the calls relate to each other. We did this in jMock1, where we used interface chaining to guide the programmer and the IDE as to what to do next. Arlo’s example is simple enough that the top-level can be inspected to see if it makes sense. I’ve worked in other domains where things are complicated enough that we really did need some checked examples to make us feel confident that we’d got it right.
1) of course, most of the world eats with their hands or chopsticks, so this is a culturally-opressive metaphor