Why We Mock Everything — Vivian Voss
On Second Thought Episode 09. The reflex is universal: to test a unit, first isolate it; to isolate it, fake everything it touches. The unit test was born pure: Kent Beck wrote SUnit for Smalltalk in 1994 and adapted it into JUnit with Erich Gamma in 1998, to test library code (parsers, algorithms, data structures, pure functions) with nothing to mock because there was no world to touch. The practice was carried wholesale into application code, which is nothing but world (a database, a queue, a payment API, a clock, a mailer), and to keep calling the tests unit tests we faked the world; dependency injection arrived to give every collaborator a seam through which a fake could be inserted, and the architecture was reshaped so the fakes would fit. Martin Fowler's 2007 essay Mocks Aren't Stubs named the classicist and mockist camps; the London school (Freeman and Pryce, Growing Object-Oriented Software, Guided by Tests, 2009) is coherent and disciplined, but the industry generalised it until unit test came to mean test with the dependencies mocked out. The cost arrives in three layers: daily friction (forty lines of mock setup to two of assertion; refactoring with no behaviour change turns fifty tests red because mockist tests assert on interactions, not behaviour); false confidence (four hundred green tests, broken checkout in production, because every dependency was a mock); and the hidden design cost (interfaces, seams and injection points that exist only to receive a mock). The most testable software ever written has no mocks at all: a Unix filter (grep, awk, sort in the FreeBSD base) is pure, text in, text out, isolated by construction because the kernel and the shell handle the world. Doug McIlroy's pipe (1973) was, in modern terms, a functional core with an imperative shell. Gary Bernhardt named that shape functional core, imperative shell in his 2012 talk Boundaries; Alistair Cockburn called it ports and adapters (hexagonal architecture, renamed 2005). A pure core needs no mocks; a thin shell needs only a few real integration tests. A mock is not a tool, it is a reading on a gauge of how far the logic was allowed to wander into the world.