What is the “Unit” in Unit Test? Or - Mocking Considered Harmful
Unfortunately, "unit test" is often understood as a test which only test a single “unit of code” like a class or component. This is a very unfortunate misunderstanding, leading to fragile tests and an overuse of mocking.
Originally “unit” refers not to a unit of code but to a unit of testing. I.e., a unit test verifies one single aspect of behavior and not depend on any other unit-test. This is the philosophy behind unit-testing frameworks: Each unit test is executed in isolation.
A unit test should not depend on the implementation details of the tested behavior and therefore not care if it is implemented in a single function or span multiple classes or modules.
Mocking should only be necessary in the case of external dependencies, like a database or external API.
Mocking classes in the same code base is an anti-pattern for several reasons:
1) Less of the actual code is tested so less errors are found. Instead the tests tests the surface of the mocks, which does not provide any particular value.
2) The test become coupled to the implementation. A major purpose of unit test is to make it safe to refactor the code because the test suite ensure it still works as expected. But with mocking, a lot of common refactorings (like splitting a class into multiple classes or the reverse) will also require rewriting the mocking setup. Changing the code under test and the test code at the same time means the benefit of the test is lost.