Recently, we were fortunate to be joined by Steve Freeman (@sf105), co-author of Growing Object-Oriented Software, Guided by Tests, and one of the early practitioners of Test-Driven Development (TDD). Steve facilitated a discussion at our weekly dev session (aka Burrito Club) on how tests can and should be used to help shape the growth and evolution of software, particularly the use of Ports and Adapters to make testability a first-class concern.
We discussed quite a range of test-related topics, including:
- Test maintenance
- Test value:
- TDD vs Design Up Front
- What to test
- How to test external dependencies (file systems, queues, etc.)
The last point was discussed at some length, and a really useful concept for system testing shared by Steve was that of Ports and Adapters (see Chapters 5 and 6 of GOOS), by which testing and testability in particular are treated as first-class citizens of the development process.
When testing our software with external systems or endpoints which we cannot change, Steve recommended that instead of using Mocks to replace the external services during testing, which can be time-consuming and difficult to maintain, you should instead use ports and adapters, which work to insulate the domain model from the implementation details of the external services/systems.
When developing software in the GOOS TDD style we want to start with the system inputs and outputs and work towards the domain model (this is different from the DDD approach, which starts from the domain model). For example, in a simple web-based system, we might have inputs from Web Services and the UI, and outputs to Persistence, Reports, Web Services and the UI (the input and output categories will likely be slightly different for each system):
Next, we add the domain model, which we can treat this as a system in its own right:
In order to insulate the core domain logic from the technical implementations, add adapters (shown here in blue) between the domain model and the technical implementations:
Finally, we add Ports to connect the Adapters to the technical implementations which provide the real service (black arrows at the outer edges):
Nat Pryce (co-author of GOOS) explains here why the Ports and Adapters scheme is such a useful approach for system testing (basically, it becomes much easier to test endpoints which are not under our control).
Non-trivial web-based systems, such as those which power thetrainline.com and our other websites, rely on a large number of external services and systems for things like payment, reservations, and fulfillment. The Ports and Adapters approach covered by GOOS is one way of reducing the testing complexity and increasing the test coverage of such software systems.