When is it safe to introduce test doubles?
I recently read this article at mockobjects.com and it reminded me of advice I give when I teach people about test doubles.
At some point after you learn how to use test doubles, and perhaps dabble with JMock or Mocha, you notice that you’re using test doubles everywhere. With any luck, you notice it, stand back, scratch your head, then wonder, “What exactly am I testing here?” If you’ve reached that stage, then you’re ready for this advice.
First, remember that everything in your system is either a Service, Entity or Value. I didn’t make those names up: I learned them from Eric Evans in Domain-Driven Design.
A value has no lifecycle, is usually immutable and behaves with value semantics. This last point mostly means that “equals” depends on the value and not the location in memory. Strings, numbers, points, lists, monetary amounts, intervals, instants in time, these are values.
An entity has a lifecycle, is usually persisted, and behaves with ID semantics. That means that two entities can look the same by value, but represent different things, and therefore aren’t equal. Think of George Foreman’s kids, all named George. If your system only stores the child’s name and its parents’ names, then all those Georges look the same, but each is unique as a snowflake. Entities often use values. People, accounts, banks, transactions, these are entities.
A service co-ordinates work and provides an API for applications to use it. A service is transient, can be pluggable and is often best when stateless. The notion of equality doesn’t much make sense for a service, and in many applications, one instance of a service is enough. (That doesn’t mean services should be singletons in the Gang of Four sense! They might be singletons in the Spring dependency injection container sense.) Services mostly figure out which entities need changing or retrieving, then either change or retrieve them. Transfer funds, deposit, withdraw, post interest, these are services.
Now that we have a common language that’s probably wrong, but suitable enough for the current purpose, here is the advice I have to offer.
Never mock values, sometimes mock entities, but mock services freely.
That’s the version that’s easy to remember. Here’s the longer answer.
If you want to mock a value, then you’re not using it as a value, or your “value” is really trying to be an entity, or worse, a service. Values just are. They don’t persist themselves, they don’t find themselves… you just instantiate them, calculate with them, then throw them away. Entities will typically hold onto them, and when entities persist, the values go with them, but typically, that’s the entity’s concern, and not the value’s. A value should be so simple that there’s no benefit to mocking them. You should have no test doubles for values. If you do, it’s time to uncover what mislaid responsibility your value has, extract it out, then try again.
You might want to mock an entity, but more likely you want to mock how you got the entity. Again, I use the term I learned from Evans: Repository. A repository is a place to look up and store entities. A repository is a service for keeping track of entities. Most of the time, I should be able to instantiate an entity and use it, so there’s no need to use a test double in its place. Typically, when you think you want to mock an entity, first try mocking the repository from whence it came.
Services, you can mock with impunity. In fact, the only time not to mock a service is when you’re testing the service. Since services are typically interfaces and pluggable, you’ll want to use test doubles when you test how the application uses the service, or how a service uses another service. Since services tend to use repositories, entities and values, when you test the service, you’ll likely use test doubles for the repositories, but not for the entities nor the values.
So that’s a summary of when I mock what. Of course, given that “mock” makes a great verb, and given the history of the term, I used mock in the foregoing mainly as a general term for “substituting a test double”, which I generally don’t like to do. I apologize for that. If this were going in a book, I’d be far more careful. There are several types of test double: mock, spy, stub, fake, dummy… I once wrote about when to fake and when to mock, so read that if you’re confused about how to use the different kinds of test doubles.
I hope you found this useful, and if you didn’t, tell me why and I’ll find a way to make it up to you.
Comments