Interpreted literally, unit testing means testing each class individually. Complete isolation is, however, difficult given that a class typically interacts with other classes. Therefore, for this definition of unit testing to hold, collaborating classes must be replaced with fakes in a test. But developers confront two main problems when using these mock objects.
First, tests become tightly coupled to mocks because the latter must be made to act precisely like the actual classes that they replace. Often, this set up becomes so complex that writing tests takes more time than writing actual classes.
Second, the class under test loses encapsulation, because it must provide ‘anchors’ for the mocks to interact with in order to fake the desired behaviour.
Still, mocks remain useful in many cases. Developers can only minimise their unpleasantness with certain approaches.
One way is to carefully consider the goal of each test. For example, is it necessary to test interactions in order to verify a given class? Could its correctness be checked differently? For example, could its state instead of its interaction be validated?
If interaction tests are necessary, developers must at least ensure that they are sensible. Mocks are fake, yet many developers inadvertently verify them in their tests. Therefore, developers must guard against this mistake.
A better way is to broaden the interpretation of ‘unit’ to a cohesive set of classes, whether it consists of one independent class or many collaborating classes. This definition grants developers the freedom to test several classes together, thus eliminating the need for mocks.