agentsclimarketplace

Sap testing quality

Skill efeumutaslan/SAP-SKILLS/skills/sap-testing-quality

23 SAP development skills for Claude Code — ABAP, RAP, CAP, Fiori, BTP, HANA, S/4HANA, Integration Suite and more. Agent Skills Specification compatible.

Install
npx -y skills add efeumutaslan/SAP-SKILLS --skill sap-testing-quality

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

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.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

12.0 KB, as published. Nobody here has run it

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:

LayerFrameworkTool
ABAP backend logicABAP UnitADT Test Runner / ATC
ABAP SQL / CDSCDS Test Double FrameworkCL_CDS_TEST_ENVIRONMENT
RAP Business ObjectsRAP BO TestEML + CL_BOTD_TXBUFDBL_BO_TEST_ENV
CAP Node.js servicescds.test + Jest/Mochacds test CLI
CAP Java servicesJUnit 5 + Spring Testmvn test
UI5/Fiori frontendOPA5 + QUnitUI5 Test Runner
API contract testingREST/OData assertionsPostman / Newman / custom
PerformanceJMeter / k6Load 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

FrameworkClassPurpose
ABAP Test Double FrameworkCL_ABAP_TESTDOUBLEMock any interface
SQL Test EnvironmentCL_OSQL_TEST_ENVIRONMENTRedirect DB tables to test data
CDS Test DoubleCL_CDS_TEST_ENVIRONMENTTest CDS views with mock data
Authority Check DoubleCL_AUNIT_AUTHORITY_CHECKStub authority checks
RAP BO Test DoubleCL_BOTD_TXBUFDBL_BO_TEST_ENVTest 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

" 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

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

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)

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

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

ErrorContextRoot CauseFix
CX_AUNIT_ASSERT_FAILEDABAP Unit assertionExpected ≠ actual valueCheck test data setup; verify production logic
CL_OSQL_TEST_ENVIRONMENT CREATE failedSQL doubleTable name wrong or not accessibleUse exact DB table name (not CDS entity name)
CDS test: no data returnedCDS test doubleRedirection not enabled or wrong entityCall enable_double_redirection( ) after create
cds.test timeoutCAP testService startup slow or DB connection issueIncrease timeout; check cds.requires for test profile
OPA5 waitFor timeoutUI5 testControl not rendered or wrong matcherIncrease timeout; verify control ID or matcher config
ATC: check cannot be suppressedATC exemptionPriority-1 findings block transportFix 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

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.