Skip to main content

sap-testing-quality

SAP testing and quality assurance skill. Use when writing ABAP Unit tests, implementing test doubles (CL_OSQL/CL_CDS/CL_BOTD), setting up CAP tests, working with ATC/Code Inspector, or building CI/CD test pipelines. If the user mentions ABAP Unit, test double, ATC check, SAP test automation, or TDD in SAP, use this skill.

Zur Installation springen

Quellinformationen

Repository
efeumutaslan/SAP-SKILLS
Letzte Quellaktivität
24. März 2026 um 21:17
Erkannte Sprache von SKILL.md
Englisch
Sterne
5
Forks
1

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
3 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
sap-testing-quality
description
SAP testing and quality assurance skill. Use when writing ABAP Unit tests, implementing test doubles (CL_OSQL/CL_CDS/CL_BOTD), setting up CAP tests, working with ATC/Code Inspector, or building CI/CD test pipelines. If the user mentions ABAP Unit, test double, ATC check, SAP test automation, or TDD in SAP, use this skill.
license
MIT
metadata
{"author":"SAP Skills Community","version":"1.0.0","last_verified":"2026-03-23"}
# SAP Testing & Quality Assurance ## Related Skills - `sap-rap-comprehensive` — RAP BO testing patterns, EML-based test assertions - `sap-devops-cicd` — Integrating tests into CI/CD pipelines, ATC in CI - `sap-fiori-testing` — wdi5/OPA5 E2E tests for Fiori/UI5 apps - `sap-abap-advanced` — ABAP Cloud test patterns with released API constraints - `sap-cloud-alm` — Cloud ALM Test Management for enterprise test orchestration ## Quick Start **Choose your testing approach:** | Layer | Framework | Tool | |-------|-----------|------| | ABAP backend logic | ABAP Unit | ADT Test Runner / ATC | | ABAP SQL / CDS | CDS Test Double Framework | `CL_CDS_TEST_ENVIRONMENT` | | RAP Business Objects | RAP BO Test | EML + `CL_BOTD_TXBUFDBL_BO_TEST_ENV` | | CAP Node.js services | cds.test + Jest/Mocha | `cds test` CLI | | CAP Java services | JUnit 5 + Spring Test | `mvn test` | | UI5/Fiori frontend | OPA5 + QUnit | UI5 Test Runner | | API contract testing | REST/OData assertions | Postman / Newman / custom | | Performance | JMeter / k6 | Load test scripts | ## Core Concepts ### ABAP Unit Architecture - **Test classes**: Local class with `FOR TESTING` addition - **Risk levels**: `HARMLESS`, `DANGEROUS`, `CRITICAL` — controls what DB changes are allowed - **Duration**: `SHORT` (<1s), `MEDIUM` (<10s), `LONG` (>10s) - **Test isolation**: Use test doubles to isolate unit under test from DB, authority checks, etc. - **Test relations**: `FOR TESTING RISK LEVEL` annotations on test class definition ### Test Double Frameworks | Framework | Class | Purpose | |-----------|-------|---------| | ABAP Test Double Framework | `CL_ABAP_TESTDOUBLE` | Mock any interface | | SQL Test Environment | `CL_OSQL_TEST_ENVIRONMENT` | Redirect DB tables to test data | | CDS Test Double | `CL_CDS_TEST_ENVIRONMENT` | Test CDS views with mock data | | Authority Check Double | `CL_AUNIT_AUTHORITY_CHECK` | Stub authority checks | | RAP BO Test Double | `CL_BOTD_TXBUFDBL_BO_TEST_ENV` | Test RAP BOs without DB | ### ATC (ABAP Test Cockpit) - Centralized quality gate for ABAP code - Runs: syntax check, naming conventions, performance patterns, security checks, custom checks - Integrable into CI/CD via `ABAP Environment Pipeline` or API - Exemptions managed via `ATC Exemption` workflow ## Common Patterns ### Pattern 1: ABAP Unit with Test Doubles ```abap " Production class CLASS zcl_order_validator DEFINITION PUBLIC. PUBLIC SECTION. INTERFACES zif_order_validator. METHODS constructor IMPORTING io_order_repo TYPE REF TO zif_order_repository. PRIVATE SECTION. DATA mo_repo TYPE REF TO zif_order_repository. ENDCLASS. CLASS zcl_order_validator IMPLEMENTATION. METHOD constructor. mo_repo = io_order_repo. ENDMETHOD. METHOD zif_order_validator~validate. DATA(ls_order) = mo_repo->get_order( iv_order_id ). IF ls_order-amount <= 0. APPEND VALUE #( type = 'E' message = 'Amount must be positive' ) TO rt_messages. ENDIF. ENDMETHOD. ENDCLASS. " Test class CLASS ltcl_order_validator DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. PRIVATE SECTION. DATA mo_cut TYPE REF TO zcl_order_validator. DATA mo_repo_mock TYPE REF TO zif_order_repository. METHODS setup. METHODS invalid_amount FOR TESTING. METHODS valid_order FOR TESTING. ENDCLASS. CLASS ltcl_order_validator IMPLEMENTATION. METHOD setup. mo_repo_mock = CAST #( cl_abap_testdouble=>create( 'ZIF_ORDER_REPOSITORY' ) ). mo_cut = NEW #( io_order_repo = mo_repo_mock ). ENDMETHOD. METHOD invalid_amount. " Arrange DATA(ls_order) = VALUE zs_order( order_id = 'ORD001' amount = -100 ). cl_abap_testdouble=>configure_call( mo_repo_mock )->returning( ls_order )->and_expect( )->is_called_once( ). mo_repo_mock->get_order( 'ORD001' ). " Act DATA(lt_messages) = mo_cut->zif_order_validator~validate( 'ORD001' ). " Assert cl_abap_unit_assert=>assert_not_initial( lt_messages ). cl_abap_unit_assert=>assert_equals( exp = 'E' act = lt_messages[ 1 ]-type ). " Verify mock cl_abap_testdouble=>verify_expectations( mo_repo_mock ). ENDMETHOD. METHOD valid_order. DATA(ls_order) = VALUE zs_order( order_id = 'ORD002' amount = 500 ). cl_abap_testdouble=>configure_call( mo_repo_mock )->returning( ls_order ). mo_repo_mock->get_order( 'ORD002' ). DATA(lt_messages) = mo_cut->zif_order_validator~validate( 'ORD002' ). cl_abap_unit_assert=>assert_initial( lt_messages ). ENDMETHOD. ENDCLASS. ``` ### Pattern 2: SQL Test Environment ```abap CLASS ltcl_order_report DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. PRIVATE SECTION. CLASS-DATA go_sql_env TYPE REF TO if_osql_test_environment. CLASS-METHODS class_setup. CLASS-METHODS class_teardown. METHODS total_by_customer FOR TESTING. ENDCLASS. CLASS ltcl_order_report IMPLEMENTATION. METHOD class_setup. go_sql_env = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( 'ZORDERS' ) ( 'ZCUSTOMERS' ) ) ). ENDMETHOD. METHOD class_teardown. go_sql_env->destroy( ). ENDMETHOD. METHOD total_by_customer. " Arrange — insert test data into double go_sql_env->clear_doubles( ). go_sql_env->insert_test_data( EXPORTING i_data = VALUE zt_orders( ( order_id = 'O1' customer_id = 'C1' amount = '100.00' ) ( order_id = 'O2' customer_id = 'C1' amount = '250.00' ) ( order_id = 'O3' customer_id = 'C2' amount = '75.00' ) ) ). " Act DATA(lt_result) = NEW zcl_order_report( )->get_totals_by_customer( ). " Assert cl_abap_unit_assert=>assert_equals( exp = 2 act = lines( lt_result ) ). READ TABLE lt_result INTO DATA(ls_c1) WITH KEY customer_id = 'C1'. cl_abap_unit_assert=>assert_equals( exp = '350.00' act = ls_c1-total ). ENDMETHOD. ENDCLASS. ``` ### Pattern 3: CDS Test Double Framework ```abap CLASS ltcl_cds_view DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. PRIVATE SECTION. CLASS-DATA go_cds_env TYPE REF TO if_cds_test_environment. CLASS-METHODS class_setup. CLASS-METHODS class_teardown. METHODS active_orders_only FOR TESTING. ENDCLASS. CLASS ltcl_cds_view IMPLEMENTATION. METHOD class_setup. go_cds_env = cl_cds_test_environment=>create( i_for_entity = 'ZI_ORDER' ). go_cds_env->enable_double_redirection( ). ENDMETHOD. METHOD class_teardown. go_cds_env->destroy( ). ENDMETHOD. METHOD active_orders_only. " Insert test data into underlying tables via SQL doubles DATA lt_orders TYPE TABLE OF zorders. lt_orders = VALUE #( ( order_id = 'O1' status = 'ACTIVE' amount = '100.00' ) ( order_id = 'O2' status = 'CLOSED' amount = '200.00' ) ). go_cds_env->insert_test_data( i_data = lt_orders ). " Execute CDS view SELECT * FROM zi_order INTO TABLE @DATA(lt_result). " Assert: only active orders returned (CDS has WHERE status = 'ACTIVE') cl_abap_unit_assert=>assert_equals( exp = 1 act = lines( lt_result ) ). cl_abap_unit_assert=>assert_equals( exp = 'O1' act = lt_result[ 1 ]-OrderId ). ENDMETHOD. ENDCLASS. ``` ### Pattern 4: CAP Node.js Test (cds.test) ```javascript const cds = require('@sap/cds'); const { expect } = cds.test('serve', '--project', __dirname + '/..'); describe('OrderService', () => { it('should create an order', async () => { const { data } = await cds.run(INSERT.into('Orders').entries({ ID: 'uuid-001', item: 'Laptop', quantity: 2, amount: 2000 })); expect(data).to.exist; }); it('should reject negative amount', async () => { try { await cds.run(INSERT.into('Orders').entries({ ID: 'uuid-002', item: 'Phone', quantity: 1, amount: -100 })); expect.fail('Should have thrown'); } catch (e) { expect(e.code).to.equal(400); expect(e.message).to.include('amount'); } }); it('should return only active orders via API', async () => { const response = await cds.test.get('/odata/v4/OrderService/Orders?$filter=status eq \'ACTIVE\''); expect(response.status).to.equal(200); response.data.value.forEach(order => { expect(order.status).to.equal('ACTIVE'); }); }); }); ``` ### Pattern 5: OPA5 UI5 Integration Test ```javascript sap.ui.define([ "sap/ui/test/opaQunit", "sap/ui/test/Opa5", "sap/ui/test/matchers/Properties", "sap/ui/test/actions/Press" ], function (opaTest, Opa5, Properties, Press) { "use strict"; opaTest("Should display order list", function (Given, When, Then) { Given.iStartMyApp(); Then.onTheOrderList.iShouldSeeTheTable(); }); opaTest("Should navigate to detail on press", function (Given, When, Then) { When.onTheOrderList.iPressOnFirstItem(); Then.onTheOrderDetail.iShouldSeeTheObjectHeader(); Then.iTeardownMyApp(); }); Opa5.createPageObjects({ onTheOrderList: { actions: { iPressOnFirstItem: function () { return this.waitFor({ controlType: "sap.m.ColumnListItem", matchers: new Properties({ type: "Navigation" }), actions: new Press(), success: function () { Opa5.assert.ok(true, "Pressed first item"); } }); } }, assertions: { iShouldSeeTheTable: function () { return this.waitFor({ id: "orderTable", success: function () { Opa5.assert.ok(true, "Table visible"); } }); } } } }); }); ``` ## Error Catalog | Error | Context | Root Cause | Fix | |-------|---------|------------|-----| | `CX_AUNIT_ASSERT_FAILED` | ABAP Unit assertion | Expected ≠ actual value | Check test data setup; verify production logic | | `CL_OSQL_TEST_ENVIRONMENT CREATE failed` | SQL double | Table name wrong or not accessible | Use exact DB table name (not CDS entity name) | | `CDS test: no data returned` | CDS test double | Redirection not enabled or wrong entity | Call `enable_double_redirection( )` after create | | `cds.test timeout` | CAP test | Service startup slow or DB connection issue | Increase timeout; check `cds.requires` for test profile | | `OPA5 waitFor timeout` | UI5 test | Control not rendered or wrong matcher | Increase timeout; verify control ID or matcher config | | `ATC: check cannot be suppressed` | ATC exemption | Priority-1 findings block transport | Fix the code; P1 findings cannot be exempted | ## Performance Tips 1. **Test isolation** — Each test method independent; use `setup` for fresh state 2. **`RISK LEVEL HARMLESS`** — Fastest execution; no DB rollback overhead 3. **Minimize test doubles** — Only double external dependencies; test real logic 4. **Parallel ATC** — Run ATC checks in parallel in CI; each object type independently 5. **CAP test profiles** — Use `[test]` profile in `.cdsrc.json` with SQLite for speed 6. **OPA5 `autoWait`** — Enable `autoWait: true` in OPA config to avoid flaky tests 7. **Test data builders** — Create helper methods for test data; reduce duplication across test methods ## Gotchas - **ABAP test double limitations**: Only works with interfaces, not concrete classes — design for dependency injection - **SQL double scope**: `CL_OSQL_TEST_ENVIRONMENT` doubles apply to the entire test class, not per method — use `clear_doubles( )` in setup - **CDS entity vs. DB table**: `CL_CDS_TEST_ENVIRONMENT` takes the CDS entity name; `CL_OSQL_TEST_ENVIRONMENT` takes the DB table name - **ATC in ABAP Cloud**: Some classic ATC checks don't apply; ABAP Cloud has its own check set - **OPA5 async pitfalls**: All OPA assertions are async; never use synchronous checks after `waitFor` - **CAP test DB**: By default `cds test` uses in-memory SQLite; HANA-specific SQL won't work — use `[test]` profile with HANA for integration tests
Auf GitHub ansehen