The book “Growing Object-Oriented Software Guided by Tests”, written by distinguished London programmers Steve Freeman and Nat Pryce, illustrates the “London school” approach centered on strict application of the Dependency Inversion and Interface Segregation Principles, which involves heavy and highly-effective use of test doubles.
Detroit-adjacent programmers Ron Jeffries and Chet Hendrickson (along with several non-Detroit-adjacent programmers like Joshua Kerievsky, James Shore and Arlo Belshee) exemplify the “Detroit school” approach which centers on a more intuitive and direct application of the Four Elements of Simple Design, in which they avoid test doubles and use the resulting tension to guide them towards designs that better reflect the Single Responsibility Principle.
The London school approach feels more like methodical, safe, steady design, whereas the Detroit school approach feels more exploratory or meandering (in the good sense, like wandering through a garden, unworried about the path, trusting that I’ll get where I need to go).
Some critics of the Detroit school dislike the feeling of having to forget what they already know about design and re-discover everything from first principles; some critics of the London school feel that test doubles lock their design in and resist change.
I see it another way: the Detroit school allows me to meander safely when I have a general idea of the destination, but an unclear picture of the route; the London school encourages me to build tiny things and put them together, and when I find that a piece needs to change shape, I can throw that piece away and design a new one in its place without paying a prohibitive cost for it.
I think of the London school approach as a shortcut that I can take when I think I recognise what I need to build and the Detroit school approach on which I can fall back when I just don’t know what to do next.
Indeed you really ought to throw a non-deterministic test away, since if you don’t it has an infectious quality.
If you have a suite of 100 tests with 10 non-deterministic tests in them, than that suite will often fail.
Initially people will look at the failure report and notice that the failures are in non-deterministic tests, but soon they’ll lose the discipline to do that.
Once that discipline is lost, then a failure in the healthy deterministic tests will get ignored too.
At that point you’ve lost the whole game and might as well get rid of all the tests.
Be careful when an asynchronous test asserts that the system returns to a previous state.
Unless it also asserts that the system enters an intermediate state before asserting the initial state, the test will run ahead of the system.
To stop the test running ahead of the system, we must add assertions that wait for the system to enter an intermediate state.