Mocks Are A Sometimes Food
By Adrian Sutton
There’s an interesting pattern when you start doing TDD and trying to make your tests as atomic as possible1. First of all you wonder how anyone could ever get far with completely standalone classes that don’t interact with anything – obviously a program needs some level of communication between classes. Then you discover Mock objects. These wonderful little gems allow you to have communication between classes but still test them independently. Pretty soon you’re going on a cookie monster style binge session with mocks. Everything can should and will be mocked out and there’s no longer any need to worry about making your classes keep to themselves, all those external dependencies can just be mocked out.
At some point though, you get an error about the max permspace being reached. You’ve created so many mock classes that the JVM no longer has room to load class definitions. What’s worse, your atomic tests which should be running lightning fast because they’re so atomic, aren’t. This is the point where you learn that Mocks are in fact a sometimes food. They’re a nasty hack which allows you to pretend the world is all happy and isolated even though it’s not.
Now, there are certainly architectures you could use which would completely avoid the need for mocks while still allowing inter-class communication but it can become mind-bendingly difficult to work out where the heck those messages are going and the performance implications of breaking things up at this level is pretty severe. A completely separated design is often beneficial at a component level, but it’s usually impractical at the class level.
So mocks are a useful tool to help test things that need to interface with other classes but are largely independent. I’ve taken to the rule of thumb that if I need to use more than one mock in a test I’m probably doing something wrong – if I’m using more than three mocks I really need to rethink my approach.
How do other people approach the use of mocks and other related techniques?
1 – I'm not yet sure, but perhaps it would be better to focus on making them run as fast as possible, rather than as atomic as possible. They would still need to be focussed enough to make it clear where the problem is instead of just showing that this is a problem.↩
2 – possibly hidden away in the language runtime↩