Introduction
In SAP ABAP development, writing robust code is essential for ensuring the stability and reliability of applications. One powerful tool for achieving this is the ABAP Unit, which allows developers to automate the testing process and validate the behavior of their code. In this blog post, we will explore how to write ABAP unit tests specifically for table functions.
ABAP CDS – Table Functions
A CDS table function is defined in the DDL source code of a CDS data definition in the ABAP development tools for Eclipse using the statement DEFINE TABLE FUNCTION in the CDS DDL of the ABAP Core Data Services (CDS). A CDS table function includes the following (including an example that is included later in the blog):
The CDS entity (e.g., ZFLIGHTS )An AMDP function implementation ( e.g., ZCL_FLIGHT_DETAILS )
Here, we’ll use a classic example of SFLIGHT data to illustrate the creation of the query within the table function.
– Table Function CDS Entity:
The following is the table function, equipped with a parameter to facilitate filtering during selection.
@EndUserText.label: ‘Flights and its Details’
@ClientHandling.algorithm: #SESSION_VARIABLE
@ClientHandling.type: #CLIENT_DEPENDENT
define table function ZFLIGHTS
with parameters
@Environment.systemField: #CLIENT
P_mandt : abap.clnt,
P_CarrierId : s_carr_id
returns
{
key mandt : abap.clnt;
key carrierId : s_carr_id;
key connectionId : s_conn_id;
key flightDate : s_date;
name : s_carrname;
planeType : s_planetye;
seatsMax : s_seatsmax;
currencyCode : s_currcode;
}
implemented by method
ZCL_FLIGHT_DETAILS=>get_details;
– Implementation of the table AMDP function is below:
CLASS zcl_flight_details DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_amdp_marker_hdb.
CLASS-METHODS get_details FOR TABLE FUNCTION zflights.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_flight_details IMPLEMENTATION.
METHOD get_details BY DATABASE FUNCTION
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING s_flights s_carrier.
RETURN select _flight.mandt,
_flight.CarrierId,
_flight.ConnectionId,
_flight.FlightDate,
_carrier.Name,
_flight.planetype,
_flight.seatsmax,
_flight.currencyCode
from
s_flights as _flight
left outer join
s_carrier as _carrier
on _flight.mandt = _carrier.mandt and
_flight.CarrierId = _carrier.CarrierId
where _flight.mandt = :P_mandt and
_flight.CarrierId = :P_CarrierId;
ENDMETHOD.
ENDCLASS.
Setting Up an ABAP Unit Environment
Before crafting tests for table functions, it is imperative to establish the ABAP unit environment. This process entails crafting a test class along with methods to assess the functionality of the table function. Let’s initiate the creation of a class named ZCL_AUNIT_ZFLIGHTS, within which we’ll create a local test class termed LCL_CL_AUNIT_ZFLIGHTS.
CLASS lcl_cl_aunit_zflights DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PUBLIC SECTION.
CLASS-DATA: environment TYPE REF TO if_amdp_test_environment.
PRIVATE SECTION.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
ENDCLASS.
CLASS lcl_cl_aunit_zflights IMPLEMENTATION.
METHOD class_setup.
” For testing an AMDP table function which is a CDS table function source,
” 1. One would need to configure the AMDP table function class and the method name in the AMDP test configuration step.
” Here the AMDP method ‘ZCL_FLIGHT_DETAILS=>GET_DETAILS’ is a table function which is used as a source for the CDS table function ‘CDSFRWK_TF_FLIGHT_BOOKING’.
DATA(environment_config) = cl_amdp_test_environment=>create_test_configuration( ).
environment_config->add_amdp_class( ‘ZCL_FLIGHT_DETAILS’ )->add_methods_for_unit_test( VALUE #( ( ‘GET_DETAILS’ ) ) ).
environment = cl_amdp_test_environment=>create( environment_config ).
ENDMETHOD.
METHOD class_teardown.
IF environment IS NOT INITIAL.
environment->destroy( ).
ENDIF.
ENDMETHOD.
METHOD setup.
” Clears any existing test configuration on the test doubles which are set by other unit test methods.
environment->clear_doubles( ).
ENDMETHOD.
ENDCLASS.
In the method class_setup, the environment configuration is done, in which the name of the AMDP class and its method to be tested need to be given.
Mocking Data
For mocking data, we’ll create a new method named test_cds_table_function within the private section of the test class. This method will facilitate the generation of mock data for testing purposes.
PRIVATE SECTION.
METHODS test_cds_table_function FOR TESTING RAISING cx_static_check.
By default, if no client is specified, the system client will be assumed. Since I aim to demonstrate data mocking at the client level, I’ll simulate data for two distinct clients and execute the query with client-specific information.
– Procedure to mock the data:
“To get the object instance of the dependency used in the AMDP Implementation Class
DATA(lo_object) = environment->get_test_double( DEPENDENCY ).
“Set the client for which the data is being mocked
lo_object->get_view_content_config( )->for_client( CLIENT-INFO ).
“Set the content of the dependency
lo_object->get_view_content_config( )->set_content( CONTENT ).
The actual Implementation of the method is below:
METHOD test_cds_table_function.
DATA: lt_flights_001 TYPE STANDARD TABLE OF s_flights,
lt_flights_714 TYPE STANDARD TABLE OF s_flights,
lt_carrier_001 TYPE STANDARD TABLE OF s_carrier,
lt_carrier_714 type standard table of s_carrier.
lt_flights_001 = VALUE #( ( CarrierId = ‘AA’ ConnectionId = ‘0101’ FlightDate = ‘20240101’ planetype = ‘A340-600’
seatsmax = ‘330’ currencycode = ‘USD’ )
( CarrierId = ‘DL’ ConnectionId = ‘0102’ FlightDate = ‘20240201’ planetype = ‘A340-600’
seatsmax = ‘330’ currencycode = ‘USD’ )
( CarrierId = ‘DL’ ConnectionId = ‘0103’ FlightDate = ‘20240301’ planetype = ‘A340-600’
seatsmax = ‘330’ currencycode = ‘USD’ ) ).
lt_carrier_001 = VALUE #( ( carrierid = ‘AA’ Name = ‘American Airlines’ )
( carrierid = ‘DL’ Name = ‘Delta Airlines’ ) ).
lt_flights_714 = VALUE #( ( CarrierId = ‘AA’ ConnectionId = ‘0104’ FlightDate = ‘20240401’ planetype = ‘A340-600’
seatsmax = ‘330’ currencycode = ‘USD’ )
( CarrierId = ‘DL’ ConnectionId = ‘0105’ FlightDate = ‘20240501’ planetype = ‘A340-600’
seatsmax = ‘330’ currencycode = ‘USD’ )
( CarrierId = ‘DL’ ConnectionId = ‘0106’ FlightDate = ‘20240601’ planetype = ‘A340-600’
seatsmax = ‘330’ currencycode = ‘USD’ ) ).
lt_carrier_714 = VALUE #( ( carrierid = ‘AA’ Name = ‘American Airlines’ )
( carrierid = ‘DL’ Name = ‘Delta Airlines’ ) ).
” Get the test double of “S_FLIGHTS” & “S_CARRIER” from the test environment.
DATA(lo_flight) = environment->get_test_double( ‘S_FLIGHTS’ ).
DATA(lo_carrier) = environment->get_test_double( ‘S_CARRIER’ ).
lo_flight->get_view_content_config( )->for_client( ‘001’ ).
lo_carrier->get_view_content_config( )->for_client( ‘001’ ).
lo_flight->get_view_content_config( )->set_content( lt_flights_001 ).
lo_carrier->get_view_content_config( )->set_content( lt_carrier_001 ).
lo_flight->get_view_content_config( )->for_client( ‘714’ ).
lo_carrier->get_view_content_config( )->for_client( ‘714’ ).
lo_flight->get_view_content_config( )->set_content( lt_flights_714 ).
lo_carrier->get_view_content_config( )->set_content( lt_carrier_714 ).
SELECT * FROM zflights( p_carrierid = ‘DL’ ) USING CLIENT ‘714’ INTO TABLE (lt_result).
cl_abap_unit_assert=>assert_equals(
EXPORTING
act = lines( lt_result ) ” Data object with current value
exp = 2 ” Data object with expected type
).
ENDMETHOD.
While executing the query for client ‘714’, LT_RESULT acquired the following records. The assertion verifies the successful retrieval of 2 records for client ‘714’.
Introduction In SAP ABAP development, writing robust code is essential for ensuring the stability and reliability of applications. One powerful tool for achieving this is the ABAP Unit, which allows developers to automate the testing process and validate the behavior of their code. In this blog post, we will explore how to write ABAP unit tests specifically for table functions.ABAP CDS – Table Functions A CDS table function is defined in the DDL source code of a CDS data definition in the ABAP development tools for Eclipse using the statement DEFINE TABLE FUNCTION in the CDS DDL of the ABAP Core Data Services (CDS). A CDS table function includes the following (including an example that is included later in the blog):The CDS entity (e.g., ZFLIGHTS )An AMDP function implementation ( e.g., ZCL_FLIGHT_DETAILS )Here, we’ll use a classic example of SFLIGHT data to illustrate the creation of the query within the table function.- Table Function CDS Entity:The following is the table function, equipped with a parameter to facilitate filtering during selection. @EndUserText.label: ‘Flights and its Details’
@ClientHandling.algorithm: #SESSION_VARIABLE
@ClientHandling.type: #CLIENT_DEPENDENT
define table function ZFLIGHTS
with parameters
@Environment.systemField: #CLIENT
P_mandt : abap.clnt,
P_CarrierId : s_carr_id
returns
{
key mandt : abap.clnt;
key carrierId : s_carr_id;
key connectionId : s_conn_id;
key flightDate : s_date;
name : s_carrname;
planeType : s_planetye;
seatsMax : s_seatsmax;
currencyCode : s_currcode;
}
implemented by method
ZCL_FLIGHT_DETAILS=>get_details; – Implementation of the table AMDP function is below: CLASS zcl_flight_details DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_amdp_marker_hdb.
CLASS-METHODS get_details FOR TABLE FUNCTION zflights.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_flight_details IMPLEMENTATION.
METHOD get_details BY DATABASE FUNCTION
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING s_flights s_carrier.
RETURN select _flight.mandt,
_flight.CarrierId,
_flight.ConnectionId,
_flight.FlightDate,
_carrier.Name,
_flight.planetype,
_flight.seatsmax,
_flight.currencyCode
from
s_flights as _flight
left outer join
s_carrier as _carrier
on _flight.mandt = _carrier.mandt and
_flight.CarrierId = _carrier.CarrierId
where _flight.mandt = :P_mandt and
_flight.CarrierId = :P_CarrierId;
ENDMETHOD.
ENDCLASS. Setting Up an ABAP Unit Environment Before crafting tests for table functions, it is imperative to establish the ABAP unit environment. This process entails crafting a test class along with methods to assess the functionality of the table function. Let’s initiate the creation of a class named ZCL_AUNIT_ZFLIGHTS, within which we’ll create a local test class termed LCL_CL_AUNIT_ZFLIGHTS. CLASS lcl_cl_aunit_zflights DEFINITION FINAL FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.
PUBLIC SECTION.
CLASS-DATA: environment TYPE REF TO if_amdp_test_environment.
PRIVATE SECTION.
CLASS-METHODS class_setup.
CLASS-METHODS class_teardown.
METHODS setup.
ENDCLASS.
CLASS lcl_cl_aunit_zflights IMPLEMENTATION.
METHOD class_setup.
” For testing an AMDP table function which is a CDS table function source,
” 1. One would need to configure the AMDP table function class and the method name in the AMDP test configuration step.
” Here the AMDP method ‘ZCL_FLIGHT_DETAILS=>GET_DETAILS’ is a table function which is used as a source for the CDS table function ‘CDSFRWK_TF_FLIGHT_BOOKING’.
DATA(environment_config) = cl_amdp_test_environment=>create_test_configuration( ).
environment_config->add_amdp_class( ‘ZCL_FLIGHT_DETAILS’ )->add_methods_for_unit_test( VALUE #( ( ‘GET_DETAILS’ ) ) ).
environment = cl_amdp_test_environment=>create( environment_config ).
ENDMETHOD.
METHOD class_teardown.
IF environment IS NOT INITIAL.
environment->destroy( ).
ENDIF.
ENDMETHOD.
METHOD setup.
” Clears any existing test configuration on the test doubles which are set by other unit test methods.
environment->clear_doubles( ).
ENDMETHOD.
ENDCLASS. In the method class_setup, the environment configuration is done, in which the name of the AMDP class and its method to be tested need to be given. Mocking Data For mocking data, we’ll create a new method named test_cds_table_function within the private section of the test class. This method will facilitate the generation of mock data for testing purposes. PRIVATE SECTION.
METHODS test_cds_table_function FOR TESTING RAISING cx_static_check. By default, if no client is specified, the system client will be assumed. Since I aim to demonstrate data mocking at the client level, I’ll simulate data for two distinct clients and execute the query with client-specific information. – Procedure to mock the data: “To get the object instance of the dependency used in the AMDP Implementation Class
DATA(lo_object) = environment->get_test_double( DEPENDENCY ).
“Set the client for which the data is being mocked
lo_object->get_view_content_config( )->for_client( CLIENT-INFO ).
“Set the content of the dependency
lo_object->get_view_content_config( )->set_content( CONTENT ). The actual Implementation of the method is below: METHOD test_cds_table_function.
DATA: lt_flights_001 TYPE STANDARD TABLE OF s_flights,
lt_flights_714 TYPE STANDARD TABLE OF s_flights,
lt_carrier_001 TYPE STANDARD TABLE OF s_carrier,
lt_carrier_714 type standard table of s_carrier.
lt_flights_001 = VALUE #( ( CarrierId = ‘AA’ ConnectionId = ‘0101’ FlightDate = ‘20240101’ planetype = ‘A340-600’
seatsmax = ‘330’ currencycode = ‘USD’ )
( CarrierId = ‘DL’ ConnectionId = ‘0102’ FlightDate = ‘20240201’ planetype = ‘A340-600’
seatsmax = ‘330’ currencycode = ‘USD’ )
( CarrierId = ‘DL’ ConnectionId = ‘0103’ FlightDate = ‘20240301’ planetype = ‘A340-600’
seatsmax = ‘330’ currencycode = ‘USD’ ) ).
lt_carrier_001 = VALUE #( ( carrierid = ‘AA’ Name = ‘American Airlines’ )
( carrierid = ‘DL’ Name = ‘Delta Airlines’ ) ).
lt_flights_714 = VALUE #( ( CarrierId = ‘AA’ ConnectionId = ‘0104’ FlightDate = ‘20240401’ planetype = ‘A340-600’
seatsmax = ‘330’ currencycode = ‘USD’ )
( CarrierId = ‘DL’ ConnectionId = ‘0105’ FlightDate = ‘20240501’ planetype = ‘A340-600’
seatsmax = ‘330’ currencycode = ‘USD’ )
( CarrierId = ‘DL’ ConnectionId = ‘0106’ FlightDate = ‘20240601’ planetype = ‘A340-600’
seatsmax = ‘330’ currencycode = ‘USD’ ) ).
lt_carrier_714 = VALUE #( ( carrierid = ‘AA’ Name = ‘American Airlines’ )
( carrierid = ‘DL’ Name = ‘Delta Airlines’ ) ).
” Get the test double of “S_FLIGHTS” & “S_CARRIER” from the test environment.
DATA(lo_flight) = environment->get_test_double( ‘S_FLIGHTS’ ).
DATA(lo_carrier) = environment->get_test_double( ‘S_CARRIER’ ).
lo_flight->get_view_content_config( )->for_client( ‘001’ ).
lo_carrier->get_view_content_config( )->for_client( ‘001’ ).
lo_flight->get_view_content_config( )->set_content( lt_flights_001 ).
lo_carrier->get_view_content_config( )->set_content( lt_carrier_001 ).
lo_flight->get_view_content_config( )->for_client( ‘714’ ).
lo_carrier->get_view_content_config( )->for_client( ‘714’ ).
lo_flight->get_view_content_config( )->set_content( lt_flights_714 ).
lo_carrier->get_view_content_config( )->set_content( lt_carrier_714 ).
SELECT * FROM zflights( p_carrierid = ‘DL’ ) USING CLIENT ‘714’ INTO TABLE (lt_result).
cl_abap_unit_assert=>assert_equals(
EXPORTING
act = lines( lt_result ) ” Data object with current value
exp = 2 ” Data object with expected type
).
ENDMETHOD. While executing the query for client ‘714’, LT_RESULT acquired the following records. The assertion verifies the successful retrieval of 2 records for client ‘714’. ConclusionWriting ABAP unit tests holds significant importance in SAP ABAP development. Thorough testing not only confirms the accuracy of table functions but also enhances the overall stability and performance of the system. Happy Coding ? Read More Application Development Blog Posts articles
#SAP
+ There are no comments
Add yours