Unit Tests sind für RAP Services unverzichtbar. Dieses Tutorial zeigt, wie du Validierungen, Actions und Determinations systematisch testest – mit vollständigen Code-Beispielen aus dem Flugbuchungs-Szenario.
Warum RAP Services testen?
RAP Services enthalten kritische Geschäftslogik:
- Validierungen: Prüfen Datenkonsistenz vor dem Speichern
- Actions: Führen Statuswechsel und Geschäftsprozesse aus
- Determinations: Berechnen automatisch Werte
Ein Fehler in diesen Komponenten kann zu Dateninkonsistenzen oder Prozessfehlern führen. Unit Tests fangen diese Fehler frühzeitig ab.
┌─────────────────────────────────────────────────────────────┐│ RAP Business Object │├─────────────────────────────────────────────────────────────┤│ ┌───────────────┐ ┌───────────────┐ ┌─────────────────┐ ││ │ Determination │ │ Validation │ │ Action │ ││ │ setDefaults() │ │ validateDate()│ │ confirmBooking()│ ││ └───────┬───────┘ └───────┬───────┘ └────────┬────────┘ ││ │ │ │ ││ └──────────────────┼────────────────────┘ ││ │ ││ ┌────────▼────────┐ ││ │ Unit Tests │ ││ │ ltc_booking │ ││ └─────────────────┘ │└─────────────────────────────────────────────────────────────┘Test-Setup für RAP
Grundstruktur einer RAP Test-Klasse
CLASS ltc_booking DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION. CLASS-DATA mo_environment TYPE REF TO if_cds_test_environment.
CLASS-METHODS class_setup. CLASS-METHODS class_teardown.
METHODS setup. METHODS teardown.
" Test-Methoden für Validierungen METHODS test_validate_flight_date_ok FOR TESTING. METHODS test_validate_flight_date_past FOR TESTING. METHODS test_validate_passenger_name FOR TESTING.
" Test-Methoden für Actions METHODS test_confirm_booking FOR TESTING. METHODS test_cancel_booking FOR TESTING.
" Test-Methoden für Determinations METHODS test_set_initial_status FOR TESTING. METHODS test_calculate_total_price FOR TESTING.ENDCLASS.CDS Test Environment einrichten
CLASS ltc_booking IMPLEMENTATION.
METHOD class_setup. " CDS Test Environment für alle beteiligten Entitäten mo_environment = cl_cds_test_environment=>create_for_multiple_cds( i_for_entities = VALUE #( ( i_for_entity = 'ZI_FlightBooking' ) ( i_for_entity = 'ZI_Flight' ) ( i_for_entity = 'ZI_Passenger' ) ) ). ENDMETHOD.
METHOD class_teardown. mo_environment->destroy( ). ENDMETHOD.
METHOD setup. " Vor jedem Test: Testdaten zurücksetzen mo_environment->clear_doubles( ).
" Abhängige Testdaten einfügen (Flüge, Passagiere) mo_environment->insert_test_data( i_data = VALUE zi_flight_tab( ( FlightId = 'LH400' Carrier = 'LH' Connection = '0400' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 Price = '450.00' Currency = 'EUR' SeatsMax = 200 SeatsOccupied = 50 ) ( FlightId = 'LH401' Carrier = 'LH' Connection = '0401' FlightDate = cl_abap_context_info=>get_system_date( ) - 10 Price = '380.00' Currency = 'EUR' SeatsMax = 200 SeatsOccupied = 200 ) ) ).
mo_environment->insert_test_data( i_data = VALUE zi_passenger_tab( ( PassengerId = 'P001' FirstName = 'Max' LastName = 'Mustermann' ) ( PassengerId = 'P002' FirstName = 'Lisa' LastName = 'Beispiel' ) ) ). ENDMETHOD.
METHOD teardown. " Nach jedem Test: Transaktionen zurückrollen ROLLBACK ENTITIES. ENDMETHOD.
ENDCLASS.Validierungen testen
Validierungen prüfen Geschäftsregeln und füllen FAILED und REPORTED bei Fehlern.
Test: Gültiges Flugdatum
METHOD test_validate_flight_date_ok. " GIVEN: Buchung mit Flugdatum in der Zukunft DATA lt_create TYPE TABLE FOR CREATE zi_flightbooking. lt_create = VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 SeatClass = 'Y' Price = '450.00' Currency = 'EUR' ) ).
" WHEN: Buchung erstellen und committen MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM lt_create MAPPED DATA(mapped) FAILED DATA(failed) REPORTED DATA(reported).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed) REPORTED DATA(commit_reported).
" THEN: Keine Fehler erwartet cl_abap_unit_assert=>assert_initial( act = commit_failed-flightbooking msg = 'Buchung mit gültigem Datum sollte erfolgreich sein' ).
" Buchung wurde erstellt cl_abap_unit_assert=>assert_not_initial( act = mapped-flightbooking msg = 'Buchung sollte erstellt worden sein' ).ENDMETHOD.Test: Flugdatum in der Vergangenheit
METHOD test_validate_flight_date_past. " GIVEN: Buchung mit Flugdatum in der Vergangenheit DATA lt_create TYPE TABLE FOR CREATE zi_flightbooking. lt_create = VALUE #( ( %cid = 'B1' FlightId = 'LH401' PassengerId = 'P001' FlightDate = cl_abap_context_info=>get_system_date( ) - 10 SeatClass = 'Y' ) ).
" WHEN: Buchung erstellen MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM lt_create FAILED DATA(failed).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed) REPORTED DATA(commit_reported).
" THEN: Validierung sollte fehlschlagen cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'Buchung mit vergangenem Datum sollte fehlschlagen' ).
" Fehlermeldung sollte vorhanden sein cl_abap_unit_assert=>assert_not_initial( act = commit_reported-flightbooking msg = 'Fehlermeldung sollte vorhanden sein' ).
" FlightDate-Feld sollte markiert sein cl_abap_unit_assert=>assert_equals( exp = if_abap_behv=>mk-on act = commit_reported-flightbooking[ 1 ]-%element-FlightDate msg = 'FlightDate-Feld sollte als fehlerhaft markiert sein' ).ENDMETHOD.Test: Pflichtfeld-Validierung
METHOD test_validate_passenger_name. " GIVEN: Buchung ohne PassengerId DATA lt_create TYPE TABLE FOR CREATE zi_flightbooking. lt_create = VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = '' " Leer - Pflichtfeld! FlightDate = cl_abap_context_info=>get_system_date( ) + 30 SeatClass = 'Y' ) ).
" WHEN MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM lt_create.
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed) REPORTED DATA(commit_reported).
" THEN: Pflichtfeld-Fehler cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'Fehlender Passagier sollte Fehler verursachen' ).
" PassengerId-Feld markiert cl_abap_unit_assert=>assert_equals( exp = if_abap_behv=>mk-on act = commit_reported-flightbooking[ 1 ]-%element-PassengerId msg = 'PassengerId-Feld sollte markiert sein' ).ENDMETHOD.Actions testen
Actions führen Geschäftslogik aus und ändern den Zustand von Entitäten.
Test: Buchung bestätigen
METHOD test_confirm_booking. " GIVEN: Offene Buchung anlegen MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 Status = 'O' " Open SeatClass = 'Y' ) ) MAPPED DATA(mapped_create).
COMMIT ENTITIES.
" Key der erstellten Buchung DATA(lv_booking_uuid) = mapped_create-flightbooking[ 1 ]-BookingUUID.
" WHEN: Action confirmBooking ausführen MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking EXECUTE confirmBooking FROM VALUE #( ( BookingUUID = lv_booking_uuid ) ) RESULT DATA(result) FAILED DATA(failed) REPORTED DATA(reported).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
" THEN: Kein Fehler cl_abap_unit_assert=>assert_initial( act = commit_failed-flightbooking msg = 'confirmBooking sollte erfolgreich sein' ).
" Status prüfen READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( Status ) WITH VALUE #( ( BookingUUID = lv_booking_uuid ) ) RESULT DATA(lt_booking).
cl_abap_unit_assert=>assert_equals( exp = 'C' " Confirmed act = lt_booking[ 1 ]-Status msg = 'Status sollte auf Confirmed (C) gesetzt sein' ).ENDMETHOD.Test: Buchung stornieren
METHOD test_cancel_booking. " GIVEN: Bestätigte Buchung MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 Status = 'C' " Confirmed SeatClass = 'Y' ) ) MAPPED DATA(mapped_create).
COMMIT ENTITIES.
DATA(lv_booking_uuid) = mapped_create-flightbooking[ 1 ]-BookingUUID.
" WHEN: Action cancelBooking mit Grund MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking EXECUTE cancelBooking FROM VALUE #( ( BookingUUID = lv_booking_uuid %param = VALUE za_cancellation_reason( ReasonCode = 'CX' ReasonText = 'Kunde hat storniert' ) ) ) FAILED DATA(failed) REPORTED DATA(reported).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
" THEN: Kein Fehler cl_abap_unit_assert=>assert_initial( act = commit_failed-flightbooking msg = 'cancelBooking sollte erfolgreich sein' ).
" Status und Stornierungsgrund prüfen READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( Status CancellationReason ) WITH VALUE #( ( BookingUUID = lv_booking_uuid ) ) RESULT DATA(lt_booking).
cl_abap_unit_assert=>assert_equals( exp = 'X' " Cancelled act = lt_booking[ 1 ]-Status msg = 'Status sollte auf Cancelled (X) gesetzt sein' ).
cl_abap_unit_assert=>assert_equals( exp = 'Kunde hat storniert' act = lt_booking[ 1 ]-CancellationReason msg = 'Stornierungsgrund sollte gespeichert sein' ).ENDMETHOD.Test: Action mit Fehlerfall
METHOD test_confirm_already_confirmed. " GIVEN: Bereits bestätigte Buchung MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' Status = 'C' ) " Bereits Confirmed ) MAPPED DATA(mapped_create).
COMMIT ENTITIES.
DATA(lv_booking_uuid) = mapped_create-flightbooking[ 1 ]-BookingUUID.
" WHEN: Erneut confirmBooking versuchen MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking EXECUTE confirmBooking FROM VALUE #( ( BookingUUID = lv_booking_uuid ) ) FAILED DATA(failed) REPORTED DATA(reported).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed) REPORTED DATA(commit_reported).
" THEN: Fehler erwartet cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'Doppelte Bestätigung sollte fehlschlagen' ).
" Prüfen ob Fehlermeldung vorhanden cl_abap_unit_assert=>assert_bound( act = commit_reported-flightbooking[ 1 ]-%msg msg = 'Fehlermeldung sollte vorhanden sein' ).ENDMETHOD.Determinations testen
Determinations setzen automatisch Feldwerte. Sie laufen bei on modify oder on save.
Test: Initialstatus setzen
METHOD test_set_initial_status. " GIVEN: Neue Buchung ohne Status DATA lt_create TYPE TABLE FOR CREATE zi_flightbooking. lt_create = VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 SeatClass = 'Y' " Status wird NICHT gesetzt - Determination soll das machen ) ).
" WHEN: Buchung erstellen MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM lt_create MAPPED DATA(mapped).
COMMIT ENTITIES.
" THEN: Determination sollte Status auf 'O' (Open) gesetzt haben READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( Status CreatedBy CreatedAt ) WITH VALUE #( ( %cid = 'B1' ) ) RESULT DATA(lt_booking).
cl_abap_unit_assert=>assert_equals( exp = 'O' " Open act = lt_booking[ 1 ]-Status msg = 'Determination sollte Status auf Open setzen' ).
" CreatedBy sollte gefüllt sein cl_abap_unit_assert=>assert_not_initial( act = lt_booking[ 1 ]-CreatedBy msg = 'CreatedBy sollte durch Determination gesetzt sein' ).
" CreatedAt sollte gefüllt sein cl_abap_unit_assert=>assert_not_initial( act = lt_booking[ 1 ]-CreatedAt msg = 'CreatedAt sollte durch Determination gesetzt sein' ).ENDMETHOD.Test: Gesamtpreis berechnen
METHOD test_calculate_total_price. " GIVEN: Buchung mit Basispreis und Extras DATA lt_create TYPE TABLE FOR CREATE zi_flightbooking. lt_create = VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 SeatClass = 'C' " Business Class BasePrice = '450.00' Currency = 'EUR' ExtraLuggage = 2 " 2 Gepäckstücke extra MealOption = 'P' " Premium Meal ) ).
" WHEN MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM lt_create MAPPED DATA(mapped).
COMMIT ENTITIES.
" THEN: TotalPrice sollte berechnet sein READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( TotalPrice BasePrice ) WITH VALUE #( ( %cid = 'B1' ) ) RESULT DATA(lt_booking).
" Business Class: BasePrice * 2.5 = 1125.00 " Extra Luggage: 2 * 50 = 100.00 " Premium Meal: 45.00 " Total: 1270.00 DATA(lv_expected_total) = CONV wrbtr( '1270.00' ).
cl_abap_unit_assert=>assert_equals( exp = lv_expected_total act = lt_booking[ 1 ]-TotalPrice msg = |TotalPrice sollte { lv_expected_total } sein| ).ENDMETHOD.Test: Determination bei Feldänderung
METHOD test_recalculate_on_change. " GIVEN: Existierende Buchung MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' SeatClass = 'Y' " Economy BasePrice = '450.00' Currency = 'EUR' ) ) MAPPED DATA(mapped_create).
COMMIT ENTITIES.
DATA(lv_booking_uuid) = mapped_create-flightbooking[ 1 ]-BookingUUID.
" Initialer TotalPrice READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( TotalPrice ) WITH VALUE #( ( BookingUUID = lv_booking_uuid ) ) RESULT DATA(lt_initial).
DATA(lv_initial_price) = lt_initial[ 1 ]-TotalPrice.
" WHEN: SeatClass auf Business ändern MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking UPDATE FIELDS ( SeatClass ) WITH VALUE #( ( BookingUUID = lv_booking_uuid SeatClass = 'C' ) " Business Class ).
COMMIT ENTITIES.
" THEN: TotalPrice sollte neu berechnet sein READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( TotalPrice ) WITH VALUE #( ( BookingUUID = lv_booking_uuid ) ) RESULT DATA(lt_updated).
" Business Class ist teurer als Economy cl_abap_unit_assert=>assert_true( act = xsdbool( lt_updated[ 1 ]-TotalPrice > lv_initial_price ) msg = 'TotalPrice sollte nach Upgrade höher sein' ).ENDMETHOD.Mocking von Dependencies
Test mit gemockten Flugdaten
METHOD test_with_mocked_flight. " CDS Test Environment erlaubt direktes Einfügen von Testdaten " Das ersetzt die echte Datenbanktabelle
" Spezieller Flug für diesen Test mo_environment->insert_test_data( i_data = VALUE zi_flight_tab( ( FlightId = 'TEST01' Carrier = 'XX' FlightDate = cl_abap_context_info=>get_system_date( ) + 100 Price = '999.99' Currency = 'EUR' SeatsMax = 10 SeatsOccupied = 0 ) ) ).
" WHEN: Buchung für gemockten Flug MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'TEST01' PassengerId = 'P001' SeatClass = 'Y' ) ) MAPPED DATA(mapped).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
" THEN: Erfolgreich mit gemockten Daten cl_abap_unit_assert=>assert_initial( act = commit_failed-flightbooking msg = 'Buchung mit gemocktem Flug sollte funktionieren' ).ENDMETHOD.Test: Ausgebuchter Flug
METHOD test_fully_booked_flight. " GIVEN: Ausgebuchter Flug (SeatsOccupied = SeatsMax) mo_environment->clear_doubles( ). mo_environment->insert_test_data( i_data = VALUE zi_flight_tab( ( FlightId = 'FULL01' Carrier = 'LH' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 SeatsMax = 100 SeatsOccupied = 100 ) " Ausgebucht! ) ).
mo_environment->insert_test_data( i_data = VALUE zi_passenger_tab( ( PassengerId = 'P001' FirstName = 'Max' LastName = 'Mustermann' ) ) ).
" WHEN: Buchung für ausgebuchten Flug versuchen MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'FULL01' PassengerId = 'P001' SeatClass = 'Y' ) ).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed) REPORTED DATA(commit_reported).
" THEN: Fehler - Flug ausgebucht cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'Ausgebuchter Flug sollte Fehler verursachen' ).ENDMETHOD.Vollständiges Testklassen-Beispiel
CLASS ltc_flight_booking DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION. CLASS-DATA mo_environment TYPE REF TO if_cds_test_environment.
CLASS-METHODS class_setup. CLASS-METHODS class_teardown.
METHODS setup. METHODS teardown.
" === VALIDIERUNGEN === METHODS test_valid_booking FOR TESTING. METHODS test_invalid_date FOR TESTING. METHODS test_missing_passenger FOR TESTING. METHODS test_invalid_seat_class FOR TESTING.
" === ACTIONS === METHODS test_confirm_booking FOR TESTING. METHODS test_cancel_booking FOR TESTING. METHODS test_confirm_already_canceled FOR TESTING. METHODS test_reschedule_booking FOR TESTING.
" === DETERMINATIONS === METHODS test_set_initial_status FOR TESTING. METHODS test_calculate_price FOR TESTING. METHODS test_set_booking_number FOR TESTING.
" === HILFSMETHODEN === METHODS create_test_booking IMPORTING iv_cid TYPE string DEFAULT 'B1' iv_flight_id TYPE zflight_id DEFAULT 'LH400' iv_status TYPE zstatus DEFAULT 'O' RETURNING VALUE(rv_uuid) TYPE sysuuid_x16.ENDCLASS.
CLASS ltc_flight_booking IMPLEMENTATION.
METHOD class_setup. mo_environment = cl_cds_test_environment=>create_for_multiple_cds( i_for_entities = VALUE #( ( i_for_entity = 'ZI_FlightBooking' ) ( i_for_entity = 'ZI_Flight' ) ( i_for_entity = 'ZI_Passenger' ) ) ). ENDMETHOD.
METHOD class_teardown. mo_environment->destroy( ). ENDMETHOD.
METHOD setup. mo_environment->clear_doubles( ).
" Standard-Testdaten mo_environment->insert_test_data( i_data = VALUE zi_flight_tab( ( FlightId = 'LH400' Carrier = 'LH' Connection = '0400' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 Price = '450.00' Currency = 'EUR' SeatsMax = 200 SeatsOccupied = 50 ) ) ).
mo_environment->insert_test_data( i_data = VALUE zi_passenger_tab( ( PassengerId = 'P001' FirstName = 'Max' LastName = 'Mustermann' ) ) ). ENDMETHOD.
METHOD teardown. ROLLBACK ENTITIES. ENDMETHOD.
" === HILFSMETHODE === METHOD create_test_booking. MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = iv_cid FlightId = iv_flight_id PassengerId = 'P001' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 Status = iv_status SeatClass = 'Y' ) ) MAPPED DATA(mapped).
COMMIT ENTITIES.
rv_uuid = mapped-flightbooking[ 1 ]-BookingUUID. ENDMETHOD.
" === VALIDIERUNGEN === METHOD test_valid_booking. " GIVEN/WHEN DATA(lv_uuid) = create_test_booking( ).
" THEN cl_abap_unit_assert=>assert_not_initial( act = lv_uuid msg = 'Gültige Buchung sollte erstellt werden' ). ENDMETHOD.
METHOD test_invalid_date. " GIVEN: Datum in der Vergangenheit MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' FlightDate = cl_abap_context_info=>get_system_date( ) - 5 SeatClass = 'Y' ) ).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
" THEN cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'Vergangenes Datum sollte Fehler verursachen' ). ENDMETHOD.
METHOD test_missing_passenger. MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = '' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 SeatClass = 'Y' ) ).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'Fehlender Passagier sollte Fehler verursachen' ). ENDMETHOD.
METHOD test_invalid_seat_class. MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 SeatClass = 'X' ) " Ungültig ).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'Ungültige SeatClass sollte Fehler verursachen' ). ENDMETHOD.
" === ACTIONS === METHOD test_confirm_booking. DATA(lv_uuid) = create_test_booking( iv_status = 'O' ).
MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking EXECUTE confirmBooking FROM VALUE #( ( BookingUUID = lv_uuid ) ) FAILED DATA(failed).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
cl_abap_unit_assert=>assert_initial( act = commit_failed-flightbooking msg = 'confirmBooking sollte erfolgreich sein' ).
READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( Status ) WITH VALUE #( ( BookingUUID = lv_uuid ) ) RESULT DATA(lt_booking).
cl_abap_unit_assert=>assert_equals( exp = 'C' act = lt_booking[ 1 ]-Status ). ENDMETHOD.
METHOD test_cancel_booking. DATA(lv_uuid) = create_test_booking( iv_status = 'C' ).
MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking EXECUTE cancelBooking FROM VALUE #( ( BookingUUID = lv_uuid %param = VALUE za_cancellation_reason( ReasonCode = 'CX' ReasonText = 'Test-Stornierung' ) ) ).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
cl_abap_unit_assert=>assert_initial( act = commit_failed-flightbooking msg = 'cancelBooking sollte erfolgreich sein' ).
READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( Status ) WITH VALUE #( ( BookingUUID = lv_uuid ) ) RESULT DATA(lt_booking).
cl_abap_unit_assert=>assert_equals( exp = 'X' act = lt_booking[ 1 ]-Status ). ENDMETHOD.
METHOD test_confirm_already_canceled. DATA(lv_uuid) = create_test_booking( iv_status = 'X' ).
MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking EXECUTE confirmBooking FROM VALUE #( ( BookingUUID = lv_uuid ) ).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'Stornierte Buchung kann nicht bestätigt werden' ). ENDMETHOD.
METHOD test_reschedule_booking. DATA(lv_uuid) = create_test_booking( ). DATA(lv_new_date) = cl_abap_context_info=>get_system_date( ) + 60.
MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking EXECUTE rescheduleBooking FROM VALUE #( ( BookingUUID = lv_uuid %param = VALUE za_reschedule_input( NewFlightDate = lv_new_date ) ) ).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
cl_abap_unit_assert=>assert_initial( act = commit_failed-flightbooking msg = 'Umbuchung sollte erfolgreich sein' ).
READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( FlightDate ) WITH VALUE #( ( BookingUUID = lv_uuid ) ) RESULT DATA(lt_booking).
cl_abap_unit_assert=>assert_equals( exp = lv_new_date act = lt_booking[ 1 ]-FlightDate ). ENDMETHOD.
" === DETERMINATIONS === METHOD test_set_initial_status. MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 SeatClass = 'Y' ) ) MAPPED DATA(mapped).
COMMIT ENTITIES.
READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( Status ) WITH VALUE #( ( %cid = 'B1' ) ) RESULT DATA(lt_booking).
cl_abap_unit_assert=>assert_equals( exp = 'O' act = lt_booking[ 1 ]-Status msg = 'Initial-Status sollte Open (O) sein' ). ENDMETHOD.
METHOD test_calculate_price. MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 SeatClass = 'Y' BasePrice = '450.00' Currency = 'EUR' ) ) MAPPED DATA(mapped).
COMMIT ENTITIES.
READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( TotalPrice ) WITH VALUE #( ( %cid = 'B1' ) ) RESULT DATA(lt_booking).
cl_abap_unit_assert=>assert_not_initial( act = lt_booking[ 1 ]-TotalPrice msg = 'TotalPrice sollte durch Determination gesetzt sein' ). ENDMETHOD.
METHOD test_set_booking_number. MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' FlightDate = cl_abap_context_info=>get_system_date( ) + 30 SeatClass = 'Y' ) ) MAPPED DATA(mapped).
COMMIT ENTITIES.
READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( BookingNumber ) WITH VALUE #( ( %cid = 'B1' ) ) RESULT DATA(lt_booking).
cl_abap_unit_assert=>assert_not_initial( act = lt_booking[ 1 ]-BookingNumber msg = 'BookingNumber sollte automatisch generiert werden' ). ENDMETHOD.
ENDCLASS.Best Practices für RAP Tests
Test-Checkliste
| Komponente | Was testen? | Wie testen? |
|---|---|---|
| Validation | Erfolgsfall | CREATE mit gültigen Daten |
| Fehlerfall | CREATE mit ungültigen Daten | |
| Feldmarkierung | %element-FieldName prüfen | |
| Fehlermeldung | %msg prüfen | |
| Action | Erfolgsfall | EXECUTE + Status prüfen |
| Fehlerfall | EXECUTE auf ungültigem Status | |
| Mit Parameter | %param übergeben | |
| Determination | on modify | Feld nach CREATE prüfen |
| on save | Feld nach COMMIT prüfen | |
| Neuberechnung | UPDATE + Feldänderung |
Dos and Don’ts
DO:
" ✅ Testdaten in setup() vorbereitenMETHOD setup. mo_environment->clear_doubles( ). mo_environment->insert_test_data( ... ).ENDMETHOD.
" ✅ ROLLBACK ENTITIES in teardown()METHOD teardown. ROLLBACK ENTITIES.ENDMETHOD.
" ✅ Ein Test = Ein SzenarioMETHOD test_confirm_booking. " Nur confirmBooking testenENDMETHOD.
" ✅ Hilfsmethoden für WiederverwendungMETHOD create_test_booking. " Wiederverwendbare BuchungserstellungENDMETHOD.DON’T:
" ❌ Keine echten DB-Daten in TestsSELECT * FROM zflight INTO TABLE @lt_flights. " Nicht!
" ❌ Keine Abhängigkeiten zwischen TestsMETHOD test_2. " Erwartet dass test_1 bereits lief - SCHLECHT!ENDMETHOD.
" ❌ Keine zu vielen Assertions pro TestMETHOD test_everything. cl_abap_unit_assert=>... " 20 Assertions = unübersichtlichENDMETHOD.Weitere Ressourcen
- ABAP Unit Testing in ABAP Cloud - Grundlagen Unit Testing
- Test Doubles und Mocking - Mocking-Techniken
- RAP Determinations und Validations - Behavior Implementation
- RAP Actions und Functions - Action-Implementierung