Los Unit Tests son indispensables para servicios RAP. Este tutorial muestra cómo probar sistemáticamente Validaciones, Actions y Determinations, con ejemplos de código completos del escenario de reservas de vuelo.
Por qué Probar Servicios RAP?
Los servicios RAP contienen lógica de negocio crítica:
- Validaciones: Verifican la consistencia de datos antes de guardar
- Actions: Ejecutan cambios de estado y procesos de negocio
- Determinations: Calculan valores automáticamente
Un error en estos componentes puede llevar a inconsistencias de datos o fallos en procesos. Los Unit Tests detectan estos errores tempranamente.
┌─────────────────────────────────────────────────────────────┐│ RAP Business Object │├─────────────────────────────────────────────────────────────┤│ ┌───────────────┐ ┌───────────────┐ ┌─────────────────┐ ││ │ Determination │ │ Validation │ │ Action │ ││ │ setDefaults() │ │ validateDate()│ │ confirmBooking()│ ││ └───────┬───────┘ └───────┬───────┘ └────────┬────────┘ ││ │ │ │ ││ └──────────────────┼────────────────────┘ ││ │ ││ ┌────────▼────────┐ ││ │ Unit Tests │ ││ │ ltc_booking │ ││ └─────────────────┘ │└─────────────────────────────────────────────────────────────┘Configuración de Test para RAP
Estructura Básica de una Clase 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étodos de test para Validaciones METHODS test_validate_flight_date_ok FOR TESTING. METHODS test_validate_flight_date_past FOR TESTING. METHODS test_validate_passenger_name FOR TESTING.
" Métodos de test para Actions METHODS test_confirm_booking FOR TESTING. METHODS test_cancel_booking FOR TESTING.
" Métodos de test para Determinations METHODS test_set_initial_status FOR TESTING. METHODS test_calculate_total_price FOR TESTING.ENDCLASS.Configurar CDS Test Environment
CLASS ltc_booking IMPLEMENTATION.
METHOD class_setup. " CDS Test Environment para todas las entidades involucradas 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. " Antes de cada test: Restablecer datos de prueba mo_environment->clear_doubles( ).
" Insertar datos de prueba dependientes (Vuelos, Pasajeros) 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. " Después de cada test: Revertir transacciones ROLLBACK ENTITIES. ENDMETHOD.
ENDCLASS.Probar Validaciones
Las validaciones verifican reglas de negocio y llenan FAILED y REPORTED en caso de errores.
Test: Fecha de Vuelo Válida
METHOD test_validate_flight_date_ok. " GIVEN: Reserva con fecha de vuelo en el futuro 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: Crear reserva y hacer commit 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: No se esperan errores cl_abap_unit_assert=>assert_initial( act = commit_failed-flightbooking msg = 'Reserva con fecha válida debería ser exitosa' ).
" Reserva fue creada cl_abap_unit_assert=>assert_not_initial( act = mapped-flightbooking msg = 'Reserva debería haber sido creada' ).ENDMETHOD.Test: Fecha de Vuelo en el Pasado
METHOD test_validate_flight_date_past. " GIVEN: Reserva con fecha de vuelo en el pasado 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: Crear reserva 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 validación debería fallar cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'Reserva con fecha pasada debería fallar' ).
" Debería haber un mensaje de error cl_abap_unit_assert=>assert_not_initial( act = commit_reported-flightbooking msg = 'Debería existir un mensaje de error' ).
" El campo FlightDate debería estar marcado cl_abap_unit_assert=>assert_equals( exp = if_abap_behv=>mk-on act = commit_reported-flightbooking[ 1 ]-%element-FlightDate msg = 'El campo FlightDate debería estar marcado como erróneo' ).ENDMETHOD.Test: Validación de Campo Obligatorio
METHOD test_validate_passenger_name. " GIVEN: Reserva sin PassengerId DATA lt_create TYPE TABLE FOR CREATE zi_flightbooking. lt_create = VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = '' " Vacío - ¡Campo obligatorio! 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: Error de campo obligatorio cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'Pasajero faltante debería causar error' ).
" Campo PassengerId marcado cl_abap_unit_assert=>assert_equals( exp = if_abap_behv=>mk-on act = commit_reported-flightbooking[ 1 ]-%element-PassengerId msg = 'El campo PassengerId debería estar marcado' ).ENDMETHOD.Probar Actions
Las Actions ejecutan lógica de negocio y cambian el estado de las entidades.
Test: Confirmar Reserva
METHOD test_confirm_booking. " GIVEN: Crear reserva abierta 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 de la reserva creada DATA(lv_booking_uuid) = mapped_create-flightbooking[ 1 ]-BookingUUID.
" WHEN: Ejecutar 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: Sin error cl_abap_unit_assert=>assert_initial( act = commit_failed-flightbooking msg = 'confirmBooking debería ser exitoso' ).
" Verificar estado 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 = 'El estado debería estar en Confirmed (C)' ).ENDMETHOD.Test: Cancelar Reserva
METHOD test_cancel_booking. " GIVEN: Reserva confirmada 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 con motivo MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking EXECUTE cancelBooking FROM VALUE #( ( BookingUUID = lv_booking_uuid %param = VALUE za_cancellation_reason( ReasonCode = 'CX' ReasonText = 'Cliente ha cancelado' ) ) ) FAILED DATA(failed) REPORTED DATA(reported).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
" THEN: Sin error cl_abap_unit_assert=>assert_initial( act = commit_failed-flightbooking msg = 'cancelBooking debería ser exitoso' ).
" Verificar estado y motivo de cancelación 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 = 'El estado debería estar en Cancelled (X)' ).
cl_abap_unit_assert=>assert_equals( exp = 'Cliente ha cancelado' act = lt_booking[ 1 ]-CancellationReason msg = 'El motivo de cancelación debería estar guardado' ).ENDMETHOD.Test: Action con Caso de Error
METHOD test_confirm_already_confirmed. " GIVEN: Reserva ya confirmada MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM VALUE #( ( %cid = 'B1' FlightId = 'LH400' PassengerId = 'P001' Status = 'C' ) " Ya Confirmed ) MAPPED DATA(mapped_create).
COMMIT ENTITIES.
DATA(lv_booking_uuid) = mapped_create-flightbooking[ 1 ]-BookingUUID.
" WHEN: Intentar confirmBooking nuevamente 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: Se espera error cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'Confirmación duplicada debería fallar' ).
" Verificar que existe mensaje de error cl_abap_unit_assert=>assert_bound( act = commit_reported-flightbooking[ 1 ]-%msg msg = 'Debería existir un mensaje de error' ).ENDMETHOD.Probar Determinations
Las Determinations establecen valores de campo automáticamente. Se ejecutan en on modify o on save.
Test: Establecer Estado Inicial
METHOD test_set_initial_status. " GIVEN: Nueva reserva sin estado 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 NO se establece - La Determination debería hacerlo ) ).
" WHEN: Crear reserva MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM lt_create MAPPED DATA(mapped).
COMMIT ENTITIES.
" THEN: La Determination debería haber establecido Status en '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 debería establecer Status en Open' ).
" CreatedBy debería estar lleno cl_abap_unit_assert=>assert_not_initial( act = lt_booking[ 1 ]-CreatedBy msg = 'CreatedBy debería estar establecido por la Determination' ).
" CreatedAt debería estar lleno cl_abap_unit_assert=>assert_not_initial( act = lt_booking[ 1 ]-CreatedAt msg = 'CreatedAt debería estar establecido por la Determination' ).ENDMETHOD.Test: Calcular Precio Total
METHOD test_calculate_total_price. " GIVEN: Reserva con precio base y 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 piezas de equipaje extra MealOption = 'P' " Premium Meal ) ).
" WHEN MODIFY ENTITIES OF zi_flightbooking ENTITY FlightBooking CREATE FROM lt_create MAPPED DATA(mapped).
COMMIT ENTITIES.
" THEN: TotalPrice debería estar calculado 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 debería ser { lv_expected_total }| ).ENDMETHOD.Test: Determination en Cambio de Campo
METHOD test_recalculate_on_change. " GIVEN: Reserva existente 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 inicial 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: Cambiar SeatClass a 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 debería estar recalculado READ ENTITIES OF zi_flightbooking ENTITY FlightBooking FIELDS ( TotalPrice ) WITH VALUE #( ( BookingUUID = lv_booking_uuid ) ) RESULT DATA(lt_updated).
" Business Class es más cara que Economy cl_abap_unit_assert=>assert_true( act = xsdbool( lt_updated[ 1 ]-TotalPrice > lv_initial_price ) msg = 'TotalPrice debería ser mayor después del upgrade' ).ENDMETHOD.Mocking de Dependencies
Test con Datos de Vuelo Simulados
METHOD test_with_mocked_flight. " CDS Test Environment permite insertar datos de prueba directamente " Esto reemplaza la tabla real de la base de datos
" Vuelo especial para este 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: Reserva para vuelo simulado 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: Exitoso con datos simulados cl_abap_unit_assert=>assert_initial( act = commit_failed-flightbooking msg = 'Reserva con vuelo simulado debería funcionar' ).ENDMETHOD.Test: Vuelo Agotado
METHOD test_fully_booked_flight. " GIVEN: Vuelo agotado (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 ) " ¡Agotado! ) ).
mo_environment->insert_test_data( i_data = VALUE zi_passenger_tab( ( PassengerId = 'P001' FirstName = 'Max' LastName = 'Mustermann' ) ) ).
" WHEN: Intentar reservar en vuelo agotado 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: Error - Vuelo agotado cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'Vuelo agotado debería causar error' ).ENDMETHOD.Ejemplo Completo de Clase 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.
" === VALIDACIONES === 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ÉTODOS AUXILIARES === 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( ).
" Datos de prueba estándar 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.
" === MÉTODO AUXILIAR === 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.
" === VALIDACIONES === METHOD test_valid_booking. " GIVEN/WHEN DATA(lv_uuid) = create_test_booking( ).
" THEN cl_abap_unit_assert=>assert_not_initial( act = lv_uuid msg = 'Reserva válida debería ser creada' ). ENDMETHOD.
METHOD test_invalid_date. " GIVEN: Fecha en el pasado 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 = 'Fecha pasada debería causar error' ). 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 = 'Pasajero faltante debería causar error' ). 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' ) " Inválido ).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
cl_abap_unit_assert=>assert_not_initial( act = commit_failed-flightbooking msg = 'SeatClass inválido debería causar error' ). 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 debería ser exitoso' ).
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 = 'Cancelación de prueba' ) ) ).
COMMIT ENTITIES RESPONSE OF zi_flightbooking FAILED DATA(commit_failed).
cl_abap_unit_assert=>assert_initial( act = commit_failed-flightbooking msg = 'cancelBooking debería ser exitoso' ).
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 = 'Reserva cancelada no puede ser confirmada' ). 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 = 'Reprogramación debería ser exitosa' ).
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 = 'Estado inicial debería ser 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 debería estar establecido por 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 debería generarse automáticamente' ). ENDMETHOD.
ENDCLASS.Mejores Prácticas para Tests RAP
Lista de Verificación de Tests
| Componente | Qué probar? | Cómo probar? |
|---|---|---|
| Validation | Caso exitoso | CREATE con datos válidos |
| Caso de error | CREATE con datos inválidos | |
| Marcación de campo | Verificar %element-FieldName | |
| Mensaje de error | Verificar %msg | |
| Action | Caso exitoso | EXECUTE + verificar estado |
| Caso de error | EXECUTE en estado inválido | |
| Con parámetro | Pasar %param | |
| Determination | on modify | Verificar campo después de CREATE |
| on save | Verificar campo después de COMMIT | |
| Recálculo | UPDATE + cambio de campo |
Lo que Sí y lo que No
SÍ:
" Preparar datos de prueba en setup()METHOD setup. mo_environment->clear_doubles( ). mo_environment->insert_test_data( ... ).ENDMETHOD.
" ROLLBACK ENTITIES en teardown()METHOD teardown. ROLLBACK ENTITIES.ENDMETHOD.
" Un test = Un escenarioMETHOD test_confirm_booking. " Solo probar confirmBookingENDMETHOD.
" Métodos auxiliares para reutilizaciónMETHOD create_test_booking. " Creación de reserva reutilizableENDMETHOD.NO:
" No usar datos reales de BD en testsSELECT * FROM zflight INTO TABLE @lt_flights. " ¡No!
" No dependencias entre testsMETHOD test_2. " Espera que test_1 ya haya ejecutado - ¡MAL!ENDMETHOD.
" No demasiadas assertions por testMETHOD test_everything. cl_abap_unit_assert=>... " 20 assertions = confusoENDMETHOD.Recursos Adicionales
- ABAP Unit Testing en ABAP Cloud - Fundamentos de Unit Testing
- Test Doubles y Mocking - Técnicas de Mocking
- RAP Determinations y Validations - Implementación de Behavior
- RAP Actions y Functions - Implementación de Actions