Mocks
Summary
Mock is a test double whose behavior is defined inline in a test. It has expectations about the way it should be called, and a test should fail if it is not called that way. Mocks are used to test interactions between objects, and are useful in cases where there are no other visible state changes or return results that you can verify1
Example
When your code reads from a disk and you want to ensure that it doesn’t do more than one disk read, you can use a mock to verify that the method that does the read is only called once.
Issues with Mocking
- Mocking frameworks make mocking easier by reducing boilerplate, but their overuse will often make a codebase more difficult to maintain.
- Over-reliance on mocking in testing; being able to advice against mocking through things like annotations.
- Mocking severely constrains the API owner’s ability to make changes to their implementation over time, because every time a mocking framework is used for stubbing or interaction testing, it duplicates behavior provided by the API. When the API owner wants to change their API, they might find that it has been mocked thousands or even tens of thousands of times throughout codebases.
- Mocks are very likely to exhibit behavior that violates the API contract of the
type
being mocked, for instance, returningnull
for a method that can never returnnull
. Had the tests used the real implementation or a fake, the API owner could make changes to their implementation without first fixing thousands of flawed tests. - Mock-centric testing is difficult to scale, as per Google’s experience. It requires engineers to follow strict guidelines when designing the system under test, and the default behavior of most engineers at Google has been to write code in a way that is more suitable for the classical testing style.