Tests unitaires pour services RAP : Tester Validations, Actions et Determinations

Catégorie
RAP
Publié
Auteur
Johannes

Les tests unitaires sont indispensables pour les services RAP. Ce tutoriel montre comment tester systématiquement les Validations, Actions et Determinations - avec des exemples de code complets du scénario de réservation de vol.

Pourquoi tester les services RAP ?

Les services RAP contiennent une logique métier critique :

  • Validations : Vérifient la cohérence des données avant la sauvegarde
  • Actions : Exécutent des changements de statut et des processus métier
  • Determinations : Calculent automatiquement des valeurs

Une erreur dans ces composants peut entraîner des incohérences de données ou des erreurs de processus. Les tests unitaires détectent ces erreurs en amont.

┌─────────────────────────────────────────────────────────────┐
│ RAP Business Object │
├─────────────────────────────────────────────────────────────┤
│ ┌───────────────┐ ┌───────────────┐ ┌─────────────────┐ │
│ │ Determination │ │ Validation │ │ Action │ │
│ │ setDefaults() │ │ validateDate()│ │ confirmBooking()│ │
│ └───────┬───────┘ └───────┬───────┘ └────────┬────────┘ │
│ │ │ │ │
│ └──────────────────┼────────────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ Tests unit. │ │
│ │ ltc_booking │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘

Configuration des tests pour RAP

Structure de base d’une classe de test RAP

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.
" Méthodes de test pour les Validations
METHODS test_validate_flight_date_ok FOR TESTING.
METHODS test_validate_flight_date_past FOR TESTING.
METHODS test_validate_passenger_name FOR TESTING.
" Méthodes de test pour les Actions
METHODS test_confirm_booking FOR TESTING.
METHODS test_cancel_booking FOR TESTING.
" Méthodes de test pour les Determinations
METHODS test_set_initial_status FOR TESTING.
METHODS test_calculate_total_price FOR TESTING.
ENDCLASS.

Configurer le CDS Test Environment

CLASS ltc_booking IMPLEMENTATION.
METHOD class_setup.
" CDS Test Environment pour toutes les entités concernées
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.
" Avant chaque test : Réinitialiser les données de test
mo_environment->clear_doubles( ).
" Insérer les données de test dépendantes (vols, passagers)
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 = 'Dupont' )
( PassengerId = 'P002' FirstName = 'Marie' LastName = 'Martin' )
)
).
ENDMETHOD.
METHOD teardown.
" Après chaque test : Annuler les transactions
ROLLBACK ENTITIES.
ENDMETHOD.
ENDCLASS.

Tester les Validations

Les Validations vérifient les règles métier et remplissent FAILED et REPORTED en cas d’erreur.

Test : Date de vol valide

METHOD test_validate_flight_date_ok.
" GIVEN : Réservation avec date de vol dans le futur
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 : Créer la réservation et commiter
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 : Aucune erreur attendue
cl_abap_unit_assert=>assert_initial(
act = commit_failed-flightbooking
msg = 'Une réservation avec une date valide devrait réussir"
).
" La réservation a été créée
cl_abap_unit_assert=>assert_not_initial(
act = mapped-flightbooking
msg = 'La réservation devrait avoir été créée"
).
ENDMETHOD.

Test : Date de vol dans le passé

METHOD test_validate_flight_date_past.
" GIVEN : Réservation avec date de vol dans le passé
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 : Créer la réservation
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 : La validation devrait échouer
cl_abap_unit_assert=>assert_not_initial(
act = commit_failed-flightbooking
msg = 'Une réservation avec une date passée devrait échouer"
).
" Un message d'erreur devrait être présent
cl_abap_unit_assert=>assert_not_initial(
act = commit_reported-flightbooking
msg = 'Un message d''erreur devrait être présent"
).
" Le champ FlightDate devrait être marqué
cl_abap_unit_assert=>assert_equals(
exp = if_abap_behv=>mk-on
act = commit_reported-flightbooking[ 1 ]-%element-FlightDate
msg = 'Le champ FlightDate devrait être marqué comme erroné"
).
ENDMETHOD.

Test : Validation de champ obligatoire

METHOD test_validate_passenger_name.
" GIVEN : Réservation sans PassengerId
DATA lt_create TYPE TABLE FOR CREATE zi_flightbooking.
lt_create = VALUE #(
( %cid = 'B1"
FlightId = 'LH400"
PassengerId = '' " Vide - champ obligatoire !
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 : Erreur de champ obligatoire
cl_abap_unit_assert=>assert_not_initial(
act = commit_failed-flightbooking
msg = 'Un passager manquant devrait causer une erreur"
).
" Champ PassengerId marqué
cl_abap_unit_assert=>assert_equals(
exp = if_abap_behv=>mk-on
act = commit_reported-flightbooking[ 1 ]-%element-PassengerId
msg = 'Le champ PassengerId devrait être marqué"
).
ENDMETHOD.

Tester les Actions

Les Actions exécutent une logique métier et modifient l’état des entités.

Test : Confirmer une réservation

METHOD test_confirm_booking.
" GIVEN : Créer une réservation ouverte
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.
" Clé de la réservation créée
DATA(lv_booking_uuid) = mapped_create-flightbooking[ 1 ]-BookingUUID.
" WHEN : Exécuter l'action confirmBooking
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 : Pas d'erreur
cl_abap_unit_assert=>assert_initial(
act = commit_failed-flightbooking
msg = 'confirmBooking devrait réussir"
).
" Vérifier le statut
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 = 'Le statut devrait être Confirmed (C)"
).
ENDMETHOD.

Test : Annuler une réservation

METHOD test_cancel_booking.
" GIVEN : Réservation confirmée
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 avec motif
MODIFY ENTITIES OF zi_flightbooking
ENTITY FlightBooking
EXECUTE cancelBooking FROM VALUE #(
( BookingUUID = lv_booking_uuid
%param = VALUE za_cancellation_reason(
ReasonCode = 'CX"
ReasonText = 'Annulation client' ) )
)
FAILED DATA(failed)
REPORTED DATA(reported).
COMMIT ENTITIES
RESPONSE OF zi_flightbooking
FAILED DATA(commit_failed).
" THEN : Pas d'erreur
cl_abap_unit_assert=>assert_initial(
act = commit_failed-flightbooking
msg = 'cancelBooking devrait réussir"
).
" Vérifier le statut et le motif d'annulation
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 = 'Le statut devrait être Cancelled (X)"
).
cl_abap_unit_assert=>assert_equals(
exp = 'Annulation client"
act = lt_booking[ 1 ]-CancellationReason
msg = 'Le motif d''annulation devrait être enregistré"
).
ENDMETHOD.

Test : Action avec cas d’erreur

METHOD test_confirm_already_confirmed.
" GIVEN : Réservation déjà confirmée
MODIFY ENTITIES OF zi_flightbooking
ENTITY FlightBooking
CREATE FROM VALUE #(
( %cid = 'B1"
FlightId = 'LH400"
PassengerId = 'P001"
Status = 'C' ) " Déjà Confirmed
)
MAPPED DATA(mapped_create).
COMMIT ENTITIES.
DATA(lv_booking_uuid) = mapped_create-flightbooking[ 1 ]-BookingUUID.
" WHEN : Tenter confirmBooking à nouveau
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 : Erreur attendue
cl_abap_unit_assert=>assert_not_initial(
act = commit_failed-flightbooking
msg = 'Une double confirmation devrait échouer"
).
" Vérifier la présence du message d'erreur
cl_abap_unit_assert=>assert_bound(
act = commit_reported-flightbooking[ 1 ]-%msg
msg = 'Un message d''erreur devrait être présent"
).
ENDMETHOD.

Tester les Determinations

Les Determinations définissent automatiquement des valeurs de champs. Elles s’exécutent on modify ou on save.

Test : Définir le statut initial

METHOD test_set_initial_status.
" GIVEN : Nouvelle réservation sans statut
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 n'est PAS défini - la Determination doit le faire
)
).
" WHEN : Créer la réservation
MODIFY ENTITIES OF zi_flightbooking
ENTITY FlightBooking
CREATE FROM lt_create
MAPPED DATA(mapped).
COMMIT ENTITIES.
" THEN : La Determination devrait avoir défini le Status à 'O' (Open)
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 = 'La Determination devrait définir le Status à Open"
).
" CreatedBy devrait être rempli
cl_abap_unit_assert=>assert_not_initial(
act = lt_booking[ 1 ]-CreatedBy
msg = 'CreatedBy devrait être défini par la Determination"
).
" CreatedAt devrait être rempli
cl_abap_unit_assert=>assert_not_initial(
act = lt_booking[ 1 ]-CreatedAt
msg = 'CreatedAt devrait être défini par la Determination"
).
ENDMETHOD.

Test : Calculer le prix total

METHOD test_calculate_total_price.
" GIVEN : Réservation avec prix de base et 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 bagages supplémentaires
MealOption = 'P' " Repas Premium
)
).
" WHEN
MODIFY ENTITIES OF zi_flightbooking
ENTITY FlightBooking
CREATE FROM lt_create
MAPPED DATA(mapped).
COMMIT ENTITIES.
" THEN : TotalPrice devrait être calculé
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
" Bagages supplémentaires : 2 * 50 = 100.00
" Repas Premium : 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 devrait être { lv_expected_total }|
).
ENDMETHOD.

Test : Determination lors d’un changement de champ

METHOD test_recalculate_on_change.
" GIVEN : Réservation existante
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.
" TotalPrice initial
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 : Changer SeatClass en Business
MODIFY ENTITIES OF zi_flightbooking
ENTITY FlightBooking
UPDATE FIELDS ( SeatClass )
WITH VALUE #(
( BookingUUID = lv_booking_uuid
SeatClass = 'C' ) " Business Class
).
COMMIT ENTITIES.
" THEN : TotalPrice devrait être recalculé
READ ENTITIES OF zi_flightbooking
ENTITY FlightBooking
FIELDS ( TotalPrice )
WITH VALUE #( ( BookingUUID = lv_booking_uuid ) )
RESULT DATA(lt_updated).
" Business Class est plus cher qu'Economy
cl_abap_unit_assert=>assert_true(
act = xsdbool( lt_updated[ 1 ]-TotalPrice > lv_initial_price )
msg = 'TotalPrice devrait être plus élevé après l''upgrade"
).
ENDMETHOD.

Mocking des dépendances

Test avec données de vol mockées

METHOD test_with_mocked_flight.
" Le CDS Test Environment permet d'insérer directement des données de test
" Cela remplace la vraie table de base de données
" Vol spécial pour ce 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 : Réservation pour le vol mocké
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 : Succès avec les données mockées
cl_abap_unit_assert=>assert_initial(
act = commit_failed-flightbooking
msg = 'La réservation avec un vol mocké devrait fonctionner"
).
ENDMETHOD.

Test : Vol complet

METHOD test_fully_booked_flight.
" GIVEN : Vol complet (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 ) " Complet !
)
).
mo_environment->insert_test_data(
i_data = VALUE zi_passenger_tab(
( PassengerId = 'P001' FirstName = 'Max' LastName = 'Dupont' )
)
).
" WHEN : Tenter de réserver un vol complet
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 : Erreur - Vol complet
cl_abap_unit_assert=>assert_not_initial(
act = commit_failed-flightbooking
msg = 'Un vol complet devrait causer une erreur"
).
ENDMETHOD.

Exemple complet de classe de test

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.
" === VALIDATIONS ===
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.
" === MÉTHODES UTILITAIRES ===
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( ).
" Données de test standard
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 = 'Dupont' )
)
).
ENDMETHOD.
METHOD teardown.
ROLLBACK ENTITIES.
ENDMETHOD.
" === MÉTHODE UTILITAIRE ===
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.
" === VALIDATIONS ===
METHOD test_valid_booking.
" GIVEN/WHEN
DATA(lv_uuid) = create_test_booking( ).
" THEN
cl_abap_unit_assert=>assert_not_initial(
act = lv_uuid
msg = 'Une réservation valide devrait être créée"
).
ENDMETHOD.
METHOD test_invalid_date.
" GIVEN : Date dans le passé
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 = 'Une date passée devrait causer une erreur"
).
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 = 'Un passager manquant devrait causer une erreur"
).
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' ) " Invalide
).
COMMIT ENTITIES
RESPONSE OF zi_flightbooking
FAILED DATA(commit_failed).
cl_abap_unit_assert=>assert_not_initial(
act = commit_failed-flightbooking
msg = 'Une SeatClass invalide devrait causer une erreur"
).
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 devrait réussir"
).
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 = 'Annulation de test' ) )
).
COMMIT ENTITIES
RESPONSE OF zi_flightbooking
FAILED DATA(commit_failed).
cl_abap_unit_assert=>assert_initial(
act = commit_failed-flightbooking
msg = 'cancelBooking devrait réussir"
).
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 = 'Une réservation annulée ne peut pas être confirmée"
).
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 = 'Le changement de date devrait réussir"
).
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 = 'Le statut initial devrait être Open (O)"
).
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 devrait être défini par la Determination"
).
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 devrait être généré automatiquement"
).
ENDMETHOD.
ENDCLASS.

Bonnes pratiques pour les tests RAP

Checklist de test

ComposantQue tester ?Comment tester ?
ValidationCas de succèsCREATE avec données valides
Cas d’erreurCREATE avec données invalides
Marquage de champVérifier %element-FieldName
Message d’erreurVérifier %msg
ActionCas de succèsEXECUTE + vérifier le statut
Cas d’erreurEXECUTE sur statut invalide
Avec paramètrePasser %param
Determinationon modifyVérifier le champ après CREATE
on saveVérifier le champ après COMMIT
RecalculUPDATE + changement de champ

À faire et à ne pas faire

À FAIRE :

" Préparer les données de test dans setup()
METHOD setup.
mo_environment->clear_doubles( ).
mo_environment->insert_test_data( ... ).
ENDMETHOD.
" ROLLBACK ENTITIES dans teardown()
METHOD teardown.
ROLLBACK ENTITIES.
ENDMETHOD.
" Un test = Un scénario
METHOD test_confirm_booking.
" Tester uniquement confirmBooking
ENDMETHOD.
" Méthodes utilitaires pour la réutilisation
METHOD create_test_booking.
" Création de réservation réutilisable
ENDMETHOD.

À NE PAS FAIRE :

" Pas de vraies données DB dans les tests
SELECT * FROM zflight INTO TABLE @lt_flights. " Non !
" Pas de dépendances entre les tests
METHOD test_2.
" S'attend à ce que test_1 ait déjà été exécuté - MAUVAIS !
ENDMETHOD.
" Pas trop d'assertions par test
METHOD test_everything.
cl_abap_unit_assert=>... " 20 assertions = confus
ENDMETHOD.

Ressources supplémentaires