Last week at CITCON Europe Steve Freeman organised a session on mock objects focusing on the original ideas and what mock objects should be used for. Freeman started by disagreeing with the established view of mock objects as isolators for unit testing, advising developers to use mocks for object design and specifying responsibilities.
According to Freeman, the original Mock object idea came out of the Roles, Responsibilities and Collaborations object design school (Rebecca Wirfs-Brock). When applying TDD to design and develop such objects, we need to specify and test responsibilities of objects, and externally visible object state isn’t part of that. Verifying that an object matches its responsibilities requires that we “fire an event and see that the appropriate messages have been sent to its collaborators”. According to Freeman, interfaces aren’t enough to specify objects because “an interface tells you what methods you can call, not when and how to call them. it doesn’t specify the contract - this is where mocks come in.”
Freeman advises using mocks as a design tool, not primarily to isolate dependencies: “To prove that this works we need a thingy but we don’t have that thingy yet, so we define it with a mock.Work your way through the slice of a system until you get to something external”. Instead of mocking out external dependencies, Freeman suggests that “you should only mock what you own”. Answering a question about the practice of mocking out database access, he said that once the system boundary is reached, developers should define the external interface in terms of their domain, providing a concrete implementation of that interface that speaks to the external system. This way the code inside a system is isolated from external dependencies and the concrete implementation should be covered by integration tests. This idea comes from Alistair Cockburn’s Ports and Adapters architecture (also called Hexagonal Architecture), where the domain we work on is in the middle and ports help it communicate with the external world. Adapters for individual ports implement the responsibility for a particular external system integration. “Test adapters with the real thing”, suggested Freeman. In domain-driven-design this corresponds to specifying a repository for objects in the context in which we work, and then providing an implementation for that repository interface that talks to a specific database or a queueing system.
Speaking about different guidelines on when to use mocks, Freeman suggested a rule of thumb “we mock when the service changes the external world; we stub when it doesn’t change the external world - stub queries and mock actions”. However he said that teams should not be enforcing rigid rules.
As some of particularly bad ideas he’s seen and experienced with mocks, Freeman said that one of the biggest mistakes was to try to mock out standard java libraries. On a controversial topic of mocking concrete classes, Freeman said that it is generally a bad idea because that means that “you care about a dependency between objects enough to mock it but you haven’t made that relationship explicit in code”. If there is no interface defining the relationship between two classes then people won’t know which of the methods of the concrete class actually participate in the relationship. An interface suggests a role, and a class might have lots of other methods there. If the interface isn’t there then the relationship is just implicit, which will make it hard to understand and maintain these objects later. “Creating an interface also forces you to find a name for it so you might discover other things that weren’t obvious”, said Freeman. Freeman also suggested locking down all dependencies in unit tests (eg making them final), which forces developers to clear up where the dependencies are and how they are used.
Freeman’s upcoming book Growing Object Oriented Software, Guided by Tests covers this topic in more detail.
Get practical knowledge and speed up your software delivery by participating in hands-on, interactive workshops:
Get future articles, book and conference discounts by e-mail.