This exchange showed up on Twitter yesterday:
Now let me be clear here. I’m a Detroit School TDDer, one of the people after whom the school is named1. And while I have used Mocks and other test doubles, I do not use them often. This surely means that I am not as skilled with them as others are, and probably means that at least some of my concerns about them are based in ignorance. Constant readers will find nothing new about this situation.
Note my speculation in the thread, though. I wonder if there’s something about the way we learned and did TDD in Smalltalk, compared to the way one does it in a language like Java. And I wonder if there’s a difference due to the kind of problem one works on that would cause one to lean more toward mocks.
I don’t know, I just wonder. Let’s speculate a bit more …
Nothing to see here, move on.
There’s an odd thing about good Smalltalk code: most of the objects seem to do nothing much at all. You send a message to this one and he sends a message to that one and she sends a message to this other one and it returns 3, and it all unwinds and there you are. Wherever you look in good Smalltalk code to see how something is done, it always seems like the work must be being done somewhere else.
Good Smalltalk code is exceedingly, emphatically, non-procedural. Oh, sure, there are algorithms: sometimes you need a QuickSort or something. Even then, the behavior is often distributed among several objects, none of which seem to be doing much at all. Does your object have a loop and a couple of if statements in it? There must be something wrong with it.
Now the London School of TDD concerns itself very much with behavior and relationships. What does the object do? Who does it talk to? What do they say to each other? In what order do they say it? (Remember, if I’m not doing these ideas justice: London School is not my school. This is what I get of it at my current level of experience.)
To a Detroit School TDDer, this attention to relationships and conversations seems almost obsessive. We do concern ourselves with these things, but only rarely. Far more commonly, we send off a message, maybe look at what comes back from it, and remain blissfully ignorant of what goes on behind the scenes. We do use test doubles from time to time: I’ll discuss that below.
Mind you, since we get all the objects tested and all that, at some point we must have thought about, tested, and constructed everything in the operation and interaction of all the objects. But most of the time, we test results. Not just return values: we do a thing and then test to be sure that the desired result happens.
Use of Mocks in Detroit School TDD
This leads me to places where I might use test doubles. Two come to mind: “slow” operations, and operations across an interface to software that I don’t have control of.
Perhaps our system relies on a slow operation, such as a database access or an http access. When we TDD such a thing, we will often build a little object that pretends to be a database or a web address, and that responds instantly without actually exercising any of the real mechanism. This is dead center in the Mock Object territory, and Mockists have all kinds of lovely tools for building objects like this, that can even be cleverly scripted to carry out complex interactions, just as if the real thing were there. These scripted Mocks are something they’re very proud of.
A Smalltalker would more likely just code such a thing up, although if I recall correctly, there were Mock-builders available for Smalltalk as well. Generally we’d build them up because we work very incrementally – I think more incrementally than London Schoolers often do – so it is natural for our mock objects to come into being gradually.
But we do use Mocks in this kind of situation. We plug them in and out with one or another form of pluggable behavior, generating a Mock instance or a real one as needed.
Now when you do this sort of thing, you still have to test your relationship with the real database or web site or whatever you’re talking with. Whatever conversation you’ve made up with your Mocks, you must replicate and test with the real thing. This is part of why we never went that way. It seemed like redundant effort and it seemed like it would engender more complex conversations just because it would be easier to do them.2
Across an interface
The examples above go across an interface, but our motivation in doing the Mocks was to gain speed. Had the interface been incredibly fast, and had the objects on the other side belonged to us, we’d have tested them directly (and a London School person probably would not).
There are times when the code we’re talking to is plenty fast, but we don’t own it. Software libraries of all kinds are like that. (They’re a bit more rare in Smalltalk, because you generally have the source code and you might well start treating the thing as your own.) Often, the code we’re talking to, since it is made up of objects, has an “API” consisting of the public classes and methods one can talk with.
Especially when the library code isn’t ours and is updated externally, we find it useful to write tests against it. Then we can run those tests when we get a new library, and have fair confidence that the new version will work. Now, as I recall these situations, we didn’t often mock the external thing: we just tested it. But sometimes we wanted to communicate, to ourselves or the vendor, just what we expected the external code to do. In that case, we might write a mock library, returning “good” results. That would let us test our code to be sure it works when the library works, and it would let us send those tests to the provider of the external stuff, so that, hopefully, they wouldn’t send us libraries that didn’t work.
We did this very very rarely, but a mocking tool could be good for this situation.
Architecture might push toward Mocks
What follows is quite speculative: it’s part of what I was thinking when I wrote the Tweets above. Do service-oriented architectures, more distributed architectures, make test doubles more valuable?
Note that when I do use test doubles, it seems to be when there’s an arm’s length relationship, in time or space or ownership, between “my code” and “some other code”. Systems today are built more and more as assemblies of OPC (Other People’s Code). Does building things this way lead us to need Mock objects more often?
If we’re using some distributed architecture, we may have a more extended conversation with some other part of the system, rather than a single call to find something out. We’re dealing with RESTful architecture, with the need to do optimistic or pessimistic locking, and so on.
Might such an architecture drive us to focus more on the conversation – the behavior – than we would in a more monolithic architecture? It would seem that it might.
Supporting this notion is the fact that a Smalltalk application is almost always a stand-alone, integrated set of objects, all of which belong to us, except for a few exceptional ones on the edges. That integration of a Smalltalk solution might allow us to concern ourselves less with ongoing conversations.
I’m far from sure of this. If there is some truth here, it causes me to wonder about the wisdom of building applications in a way that “requires” a lot of Mock objects. Such applications are surely more complex, even if somehow “easier” to build because of the ability to use things that already exist.
There is none. This was just speculative musing. What do you think about the subject? How will these thoughts modify what you do?
You may find references to a Chicago School of TDD. I have no idea what that might be. Could refer to Bob Martin, I suppose … he’s mostly Detroit in style, having learned TDD from Kent Beck, as the Detroit School did. ↩
Note that this, too, is speculative and based in part on prejudice: if I were a wizard of Mocks, I might think differently. I would think differently: I might also reach different conclusions. ↩