How do we make monolithic legacy applications testable?

First consider whether it pays off to test parts of a legacy monolith in isolation. If the system is about to be decommissioned or “strangled”, it may prove more valuable to invest in a bunch of good system tests that verify critical functionality.

That said, unit testing a legacy monolith is about increasing its units’ controllability and observability, which is done by inserting seams and breaking dependencies, so that test doubles can be employed. Typical techniques for dependency breaking are constructor injection, setter injection, property injection, and factory method override. In a typical monolith, you’ll be using a combination of them.

Book References
Read more about these topics in Developer Testing: Building Quality into Software:

  • Chapter 4: Testability from a Developer’s Perspective, pages 43-51
  • Chapter 6: Drivers of Testability, pages 68-72
  • Chapter 9: Dependencies, pages 119-133
  • Chapter 19: Test Ideas and Heuristics, page 271