One thing that came up in a couple of sessions of Altnetconf UK was the old saw of classicist vs. mockist approaches to TDD. Martin Fowler has a great, and updated, article on the distinction between the two approaches here. Now I have to confess to being a classicist. I tried being a mockist, but I gave it up because of the dangers of over-specified software. Now I tend to favor test doubles for the areas that are difficult to get under test otherwise as per Michael Feathers. We are also much more inclined to use a stub or fake than a mock.
Now some folks seemed to feel that if you had used concrete dependencies or associations in a test, you were not writing a unit test, and thus not using TDD properly. I see the origin of the unit test mantra, Fowler calls TDD in the classicist model mini-integration tests over unit tests, but I reject the latter accusation that this is not, somehow, TDD. The spirit of TDD in my reading, of Kent Beck, never precluded the use of concrete collaborators.
Maybe its time to stop thinking about unit tests and integration tests, with the implicit zero tolerance for collaborators in unit tests, but simply tests and acceptance tests with the latter being more coarse-grained than the former.
Certainly one advantage for classicists is that we don’t get ‘an interface for everything’ and end up with ICustomer, but interfaces where actually want points of extensibility i.e. where we have role that can have multiple implementations, or at boundaries such as layers. We don’t really have to worry about using solutions such as TypeMock to mock a concrete dependency, and so avoid proliferation of interfaces, because we are often more happy with the concrete object itself.
Usefully, there seems to be a convergence between hard-to-test code for classicists, which is where we tend to deploy mocking frameworks, and the places where we need interfaces, so difficulty seems to help flush out these design points.
I would also suggest that people look to the notion of what Rebecca Wirfs-Brock and Alan McKean call sub-systems or object neighborhoods within the domain. Within a neighborhood I would have few doubts around allowing concrete collaborators in tests, it’s okay to play with the other kids in your neighborhood, but outside of that subsystem, you probably want to use a test double to reduce stranger danger. Of course the class to replace with a test double is the facade which you should pass through to get to that neighborhood anyway, once again reinforcing the notion of TDD driving good design.
Pingback: Mocks and Tell Don’t Ask