Clearing up the Mock confusion
There’s some bad blood concerning Mocks, and a lot of it rightfully so. Because of popular mocking frameworks, the name “Mock” has become interchangeable for “Test Double”. In Texas, we ask for a Kleenex, not a tissue, and a Coke instead of a soft drink. The brand name has defined the family of products, though not every soft drink is a Coke.
Because of the Mock/Test Double confusion, Mocks are used in many wrong places, where another Test Double is more appropriate. For the record:
A Test Double is a general term for a test-specific substitute. Mocks, among others, are a specific type of Test Double.
If you look through your tests and all you see are Mock Objects, chances are pretty good you’ll have some very brittle tests that are coupled tightly to the implementation of the class under test. Specific types of Test Doubles include:
- Test Stub
- Test Spy
- Mock Object
- Fake Object
- Dummy Object
A Test Stub is used to control the indirect inputs of a class under test. By setting up different values for the Test Stub, we can force our class under test down specific paths.
A Test Spy is used to capture the indirect outputs of a class under test. By capturing the indirect outputs, we can verify messages being sent by the class under test that we might not have access to otherwise. Test Stubs and Test Spies can be combined to force inputs and verify outputs.
A Mock Object is used to verify the interactions between a class under test and the Mock Object. Mock Objects verify interactions usually by incorporating Record and Replay modes, where all method calls made in the Replay mode must be set up in the Record mode. Strict Mock Objects are useful for ensuring that only the methods specified are called, and nothing more. Loose Mock Objects are useful for ensuring that specified methods are called, but extra methods called won’t cause errors.
A Fake Object is used to substitute a simpler implementation for an otherwise complex or lengthy behavior. Typically this could mean an in-memory database instead of the real thing, which provides all the functionality of the real database, but only for the lifetime of the test. For example, instead of a CustomerRepository hitting the database, the Fake Object might just use local collection objects.
A Dummy Object is used to fill a parameter for a method. Similar to Test Stubs, except no verification is done, and they’re not used to drive specific paths. As the name implies, Dummy Objects are used just so the code can compile and run.
As you can see from the description of the Mock Object, it tests a very specific scenario, interactions. Using Mock Objects in place of all the others would lead to some serious issues. Test what you mean to test, use the right Test Double for your situation, and you should come out fine in the end.