Mockist vs Classical testing strategy

We learned in the previous article the difference between Behavior vs State verification. Depending on the testing style, we use either one or the other verification style. This article is about testing style and shows how each style impacts TDD.
Mockist TDD
The mockist strategy is also known by London School strategy, Outside-in, or white box testing. The mockist TDD style tests system interactions.
Fixture Setup
The mockist TDD style create the SUT and always use mocks for its collaborators.
Design Style
Mockist TDD promotes a style called need-driven development. We first develop from the outside of the system (UI for example). We then think about expectations and interactions between the SUT and collaborators. It makes us think ahead with the implementation of the production code through the mocks. The expectations/assumptions, about mocks created, become the starting points for our other tests. We repeat the process by testing one SUT at a time. Mocks drive the design of our system.
Test Coupling
This strategy couples tests to the production code. So, if we change an object or method signature, we will have compile errors on all of our tests using these mocks. However, it is easy to point out the problem with mockist TDD because only tests whose SUT contains the bug will fail.
Classical TDD
The classicist strategy is also known by Detroit School strategy, Inside-out, black box testing, or state based testing. The classical TDD style tests system boundaries. A classic TDDer can use any test double. It might use mock if the collaboration between the SUT and the collaborator make state verification impossible.
Fixture Setup
The classical TDD style creates the SUT, and uses real objects if possible or a double if the collaborator is (cf. Test Double):
- slow to run, or
- a production service that cannot be used for testing, or
- unreliable.
It uses a factory (also called objectMother) to create them.
Design Style
This style also affects the design of our system. It can follow the same approach used with mocks, but with stubs instead. There is another approach called inside-out. We first develop the domain for the feature to work. Then, we go one layer above and create the SUT and collaborators if needed. With this strategy, we do not need to stub or mock anything. It also helps to keep domain logic from leaking into the UI.
Test Isolation
If we change an object or method signature on an object, it will not affect any test. However, if we introduce a bug in our system, many tests can fail where the buggy object is a collaborator. The use of an objectMother simplifies object creations since we can reuse objects instantiations. This is a drawback for mockist since a bug can produce a ripple effect throughout our test suite..
Conclusion
To get a good test coverage, there are many strategies. Our strategy choice depends if we prefer to focus on the result of the behavior or how it is implemented.