Practical Workflow for Testable Development
This guide provides a step-by-step workflow for applying the principles of the Testability Framework. Rather than designing everything upfront, a truly testable design often emerges from the process of writing tests first, a core concept of Test-Driven Development (TDD). This workflow encourages that mindset by starting with the smallest testable pieces and building outward.
1. Start with "Wishful Thinking": Define Your Ideal Interface
Before writing any implementation code, follow Kent Beck's rule of thumb: "Write a test that describes your ideal Object API". This practice, also known as "Wishful thinking," involves imagining that the component you want to build already exists and considering how you would ideally interact with it. This process naturally helps you define the clear, public interfaces for your components and forces you to think about the necessary dependencies, which is the first step toward creating a decoupled design.
2. A Step-by-Step Workflow Based on the Testing Pyramid
This workflow follows the structure of the testing pyramid, starting from the foundation and working up. It aligns with the practice of implementing and testing classes with no dependencies before moving to classes that depend on them.
2.1. Foundation: Build and Test Your Units First
Begin with the smallest, most independent pieces of logic. In the context of this framework, this means you should first write unit tests for your unit microflows (OPR_, VAL_, GET_, RULE_, FTN_).
- Why start here? These microflows are designed to have no dependencies on other microflows and represent the "class that does not depend on another class". They are the easiest to test in isolation, as their behavior depends only on their input parameters.
- What to test? For each unit microflow, define its preconditions (what must be true for it to run) and postconditions (what the result should be). Write tests that cover all interesting corner cases and boundary values to ensure the microflow is rock-solid. The source document
MF Orchestration for Action: SalesOrder Finalizationprovides an excellent example withVAL_sodr_finalize_add_preconditionsandOPR_lock_entity, which are perfect candidates for unit testing.
2.2. Middle Layer: Integrate and Test Orchestration
Once your units are implemented and tested, you can move on to the logic that connects them. This corresponds to writing integration tests for your orchestration microflows (ORC_).
- Why this order? An
ORC_microflow is a "class that depends on a class you already implemented". Since you have already verified the behavior of the individual units, your integration test can focus solely on whether the orchestration logic correctly composes and calls these units in the right sequence. - What to test? The goal here is to verify the execution paths. Using the TestLogger helper component, you can create assertions that check if the sequence of called unit microflows (the "footprint") is correct for a given set of inputs. This ensures the orchestration logic is sound without re-testing the detailed output of each unit. The
ORC_sodr_finalize_addmicroflow, which calls multiple units in a specific order, is a perfect example of what to target with an integration test.
2.3. Top Layer: Validate End-to-End Functional Behavior
Finally, address the public interfaces of your application by writing functional tests that target the touchpoint microflows (ACT_, PUB_, SCE_).
- Why last? Because the lower-level tests have already verified the integrity of the underlying units and their orchestration, your functional tests can be lean. They only need to confirm that the touchpoint correctly triggers the main orchestration and that the final, end-to-end outcome meets the business requirements.
- What to test? These tests should validate critical user journeys from an end-user perspective. For example, a functional test for the "Finalize Add SalesOrder" action would be triggered by calling
ACT_sodr_add_finalize. The test would provide aSalesOrderobject as input and assert the final state (e.g., theSalesOrderstatus is now "Active") and that the correct feedback message is shown to the user.
By following this iterative, "test-first" workflow, your testable design will emerge naturally, resulting in a robust, maintainable, and high-quality application.