Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
kishore_kumar_g
Explorer

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'.

 

 

Output.jpg
 
 
 
 
 
 
 
 
 
Conclusion
Writing 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 🙂
2 Comments
frankmueller9
Participant
0 Kudos

Hi Kishuar,

great blog.

I have 2 questions regarding this:

1. In which SAP Release is it available?

2. Does it work only with CDS table functions or does it work also with normal AMDP methods?

Best regards

Frank

kishore_kumar_g
Explorer

Hi @frankmueller9,

Thank you for your comments about the blog.

Regarding your questions:

  1. It is included with the SAP_BASIS Release 758, SP Level 0000, and it's accessible from OP 2023.

  2. It's not limited to CDS table functions; it also works with standard AMDP methods.

Regards,

Kishore