Test Isolation Without Mocks
In this screencast we TDD the same code twice: once in the traditional, imperative OO way with mutation; then again in a functional way by returning a value.
We look at several differences between the two implementations, but the most interesting is in the way that they're isolated. Though both are isolated against external behavior, only the OO version requires mocks. The functional version achieves isolation by taking a value in (a Tweet value object) and return a value out (an array of strings to be rendered). This saves us from the danger of mocked methods going out of sync.
Note 1: For realism, the tests are written in exactly the way that I naturally wrote them on my first practice run. This does make the OO version slightly more complicated; the mocking could be simplified but, of course, it can't be removed. Additionally, since this is how I wrote it originally, it shows how easy it is to introduce accidental complexity when mocking in tests.
Note 2: The magic numbers that I claim have "disappeared" in the functional version are still present in the padding numbers (" " * 16, etc.) This was simply sloppy language on my part; I should've said that the tests and production code together remove the magic from the numbers. The production code contains the details, whereas the tests give a clear high-level view of what's happening.