chapter seven

7 Designing for testability

 

This chapter covers

  • How to make your code more testable, at architectural, design, and implementation levels
  • The hexagonal architecture, dependency inversion and injection, observability and controllability
  • What hinders the testability of your code and how to avoid such pitfalls

I usually say that every software system can be tested; however, some are more testable than others. Some software systems can be indeed very hard to be tested. Imagine that, for a single test case, the developer needs to set up three different web services, create five different files in different folders of the system, and put the database to a specific state. After all that, the developer exercises the feature under test and, to assert the correct behavior, the developer needs again to see if the three web services were invoked, that the five files were consumed correctly, and that the database is now on a different state. All those steps are totally doable; however, I ask: Could this not be simpler?

7.1 Separate the infrastructure from the domain code

7.2 Dependency injection and controllability

7.3 Make your classes and methods observable

7.3.1 Example 1: Introducing methods to facilitate assertions

7.3.2 Example 2: Observing the behavior of void methods

7.4 Dependency via class constructor or value via method parameter?

7.5 Design for testability in the real world

7.5.1 The cohesion of the class under test

7.5.2 The coupling of the class under test

7.5.3 Complex conditions and testability

7.5.4 Private methods and testability

7.5.5 Static methods, singletons, and testability

7.5.6 The Hexagonal Architecture and mocks as a design technique

7.6 Summary

7.7 References