Lesson 5 of 5
Designing for testability
10 min
Listen to this lesson
An architecture is testable when each part can be tested on its own, the parts can be tested together in an environment that predicts production, and the tests can run again cheaply. Testability is a design property. If nobody asks for it during design, the team discovers at the first regression cycle that an extension can only be tested by clicking through production-like data by hand.
Contracts between the parts
Released APIs and events are contracts: the provider promises a shape and behavior, the consumer relies on it. Clean core extensions sit on these contracts, which is exactly what makes them testable. A contract test checks that the provider still honors the promise (fields, types, error codes, paging) and that the consumer handles everything the contract allows, including errors. Contoso keeps contract tests for each released API the fleet order status app uses, and runs them against CMQ after every transport import and against the upgraded system at every stack.
- UnitApp logic and the customer filter tested in isolation with mocked API responses
- ContractCalls to the released APIs checked against the expected structure and errors
- IntegrationApp in cmc-ext-test calls CMQ through the real destination and Cloud Connector
- End to endA Great Lakes test user signs in, sees only its orders, and the ASN arrives in the partner test system
- OperationalSynthetic monitoring check and alert routing verified before go-live
Environments and test doubles
Each BTP stage pairs with an ERP tier, so integration tests run where both sides are production-like. Not every dependency is always available, though. Partner systems go down, and some events are hard to produce on demand. Test doubles, such as mocked API responses or a simulated partner endpoint, keep fast tests running; they never replace a final integration test against the real counterpart. SAP's DevOps guidance for integration content lists what to test before promoting a flow: contracts, mappings, authorization failures, duplicate delivery and back-end outages. Each of those is far easier to test when the design allows the dependency to be swapped or simulated.
| Design choice | Testable design | Hard-to-test design |
|---|---|---|
| Back-end access | Through a named destination per stage | Hard-coded host names in code |
| Events | Consumer can be fed a recorded event in test | Only a real posting in SAP S/4HANA triggers it |
| Security filter | A separate, unit-testable function | Mixed into UI code and SQL strings |
| Configuration | Kept out of the deployable artifact | Baked into the build, different per stage |
| Errors | Documented error responses the consumer handles | Generic failures with no code |
Test data deserves a design too. The fleet order status app needs sales orders for at least two customers in CMQ, so the customer filter can be proven both ways, plus orders in every status the app displays. Contoso keeps a small, documented data set for this, recreated after each CMQ refresh by a data preparation script, and test users for two fictional fleet customers in the test identity tenant. Without that data, the most important negative test (one customer cannot see another customer's orders) cannot be run at all.
Automation in the pipeline
SAP's DevOps reference architecture uses SAP Continuous Integration and Delivery: a pipeline, chosen from templates for typical BTP use cases such as side-by-side extensions, qualifies each change by running the tests the template proposes, and after the tests pass it can hand the result to SAP Cloud Transport Management for controlled promotion. Teams can add other test frameworks to the pipeline with additional commands. For UI tests, component tests and end-to-end browser tests in the style of OPA5 and wdi5 suit SAPUI5 and Fiori elements apps; for ABAP on-stack logic, ABAP Unit plays the same role. The pipeline makes the fast layers run on every change; the slower layers run per release in the test and pre-production stages.
- Every commitUnit and contract testsPipeline in the development stage; failures stop the build
- Every transport to testIntegration testscmc-ext-test against CMQ, real destinations
- Every releaseEnd-to-end and regressionRecorded in SAP Cloud ALM with evidence
- Before each release and stackRehearsal and operational checkscmc-ext-preprod against CMR; monitoring and runbooks verified
What would you do?
During design review, Kenji's BTP developer says the fleet order status app's customer filter is "inside the SQL in the UI service" and can only be tested end to end. What should the architect ask for?
- Testability is a design property: ask for it at design review.
- Released APIs and events are contracts; contract tests protect both sides.
- Layer tests from unit to end to end; test doubles speed up the fast layers but never replace final integration.
- Pipelines run fast tests on every change; slower layers run per release in test and pre-production stages.
Check your understanding · not graded
Lesson check
1. What does a contract test check?
2. What is the right role of test doubles such as mocked API responses?
3. Which SAP service runs CI/CD pipelines from templates for BTP use cases?
4. Which design choice makes an extension easier to test across stages?