Is there a testable architecture?

Testing has been part of the software development process since the begining of the field. In the traditional mathodology testing was used to be a cascade and happened before the software was produced. The shift in the industry with agile methodologies shifted the testing aspect of it to be part of the development process in a iterative fashion.

Despite the iterative process, testability often emerges as a key quality attribute of robust software architecture. Notably, the concept of testability has been explored in various contexts, from architectural patterns like Ports and Adapters to a broader set of attributes outlined in foundational literature. Testing is and should be taking into account as a foundation topic.

One compelling perspective comes from the Cucumber framework, which describes Ports and Adapters as a “testable architecture” [1]. This architectural style emphasizes separating core business logic from external dependencies, such as databases or APIs. By decoupling these components, Ports and Adapters make it easier to isolate and test the system’s core functionality, enabling a clean separation between behavior and implementation details.

On the other hand, the fourth edition of Software Architecture in Practice takes a broader view. Chapter 12, dedicated to testability, defines it not as an architectural style but as a collection of attributes that enhance a system’s ability to be tested. These attributes—observability, controllability, and isolatability, among others—serve as building blocks for a testable architecture. This broader perspective opens the door for various architectural styles, not just Ports and Adapters, to qualify as testable depending on how well they align with these attributes.

Attributes of Testable Architectures

The importance of listing attributes rather than naming a single architectural style lies in its inclusivity. By focusing on attributes, we can evaluate and design architectures that meet the unique needs of a system while ensuring they remain testable. Let’s explore some of these key attributes:

  • Observability: A testable architecture provides mechanisms to monitor and log system behavior, making it easier to diagnose issues during testing.
  • Controllability: The ability to inject and manipulate test data ensures that specific scenarios can be reliably reproduced and validated.
  • Isolatability: Components or modules can be tested independently without relying on external systems, reducing the complexity of test setups.

These attributes depict a broader picture of testability, highlighting the flexibility of applying the concept to various architectural styles, such as microservices, monoliths, or event-driven systems.

Balancing Testability with Other Architectural Attributes

Software architecture is rarely about optimizing a single quality attribute. Beyond testability, architects must consider:

  • Complexity: While decoupling components improves testability, it may also increase overall system complexity. For instance, Ports and Adapters introduce additional layers, which require careful management.
  • Security: A secure architecture may impose constraints that impact testability, such as restricting access to sensitive data or systems.
  • Scalability: Ensuring that an architecture scales under load can sometimes conflict with simplifying the design for easier testing.

These trade-offs illustrate why testability should be considered alongside other quality attributes when designing a system.

Testability as a Design Principle

Ultimately, the key takeaway from Software Architecture in Practice is that architecture is defined by its quality attributes. Testability, as one such attribute, provides a lens through which to evaluate and refine system design. By understanding and applying attributes like observability, controllability, and isolatability, architects can create systems that are not only functional but also maintainable, reliable, and easier to test.

There are other things beyond

Often, Hexaggonal architecture is related to a “testable” architecture leading to developers to believe that the layered are somehow not suitable for efficient testing.

The book Understanding ASP. NET MVC by John Ciliberti label MVC app as a testable approach [2]. Indeed he highlights as this being an advantage of this style. The same happens to Nathan Rozentals in his book “Mastering TypeScript 3”, he states: “this MV* style of building applications also brings with it an advantage: the ability to write testable JavaScript. Using MV* allows us to unit test, integration test, and acceptance test almost all of our beautifully hand-crafted JavaScript” [3].

Testability is more than just an architectural style—it’s a principle grounded in a system’s attributes. While Ports and Adapters provide a concrete example of a testable architecture, the broader set of attributes outlined in Software Architecture in Practice reminds us that testability is versatile and context-dependent. As you design your next system, consider how testability can be integrated alongside other architectural priorities, ensuring a balanced and resilient solution.

References

  1. [1]Cucumber.io, “Testable Architecture,” 2022 [Online]. Available at: https://cucumber.io/docs/guides/testable-architecture. [Accessed: 01-May-2022]
  2. [2]J. Ciliberti, “Understanding ASP.NET MVC,” in ASP.NET MVC 4 Recipes: A Problem-Solution Approach, Berkeley, CA: Apress, 2013, pp. 15–57 [Online]. Available at: https://doi.org/10.1007/978-1-4302-4774-6_2
  3. [3]N. Rozentals, Mastering TypeScript 3: Build enterprise-ready, industrial-strength web applications using TypeScript 3 and modern frameworks. Packt Publishing Ltd, 2019.