2 ms·
After these essays and the scuttle on Twitter, to me this whole debate is not about TDD per se, it's about how far you take "architect for testing". Purists li
by parasubvert 13y ago
After these essays and the scuttle on Twitter, to me this whole debate is not about TDD per se, it's about how far you take "architect for testing".
Purists like to create a pure in-memory application or domain model with no framework or external system dependencies, with adapter layers to isolate such dependencies. Some call this a "hexagonal" architecture, after an essay written by Alistair Cockburn, where your core code exposes ports to the various external hooks, whether a GUI, REST API, database, notification system, etc, and your TDD drives against these ports.
The benefit is that your core unit tests run very fast and allow you to move very quickly with the core code, and to refactor things quickly. The drawback is that your end-to-end integration and acceptance tests tend to be brittle since they often wind up being deferred to late in your iteration or release.
DHH on the other hand built a pretty popular set of patterns and frameworks (ActiveRecord and Rails), and really doesn't see any value with a codebase isolating itself from those things. Layers of indirection defeat the productivity benefits of these patterns and frameworks, and also give a false sense of comfort with the quality of end-to-end integration.
For example, to some, unit testing with a database in the mix is a no-no. To others, it's fine if you can make it fast and predictable (eg. Swapping in an In memory SQL store with test data). Another example is TDD from the UI through Selenium, Watir or Capybara.
Uncle Bob is saying actually he's fine with such dependencies if you can meet the speed and reliability targets of a pure model. And if you can deal with the coupling you've introduced.
To me, TDD is about whether you write your tests before your code, and that each test is isolated from other test contexts. As long as you setup and tear down your context quickly and reliably, you can include whatever dependencies that make sense as part of your daily development activities. Your level of coupling to a framework is a tradeoff of productivity today vs future proofing.
The clear "wrong way" practiced by some inexperienced TDDers is to not design a hexagonal architecture at all (ie. don't build clear APIs and SPIs and test outside in!) and to mock every external dependency, testing from the inside of your application out. This bakes implementation details into your test cases and makes everything brittle.