Thursday, 22 March 2018

ABAP Unit Test for Odata Services

The intent of this blog is to describe how to create local unit test classes for Odata services.

Example Considered


In order to keep things simple we have created an Odata service which returns the description of the document type (AUART from TVAKT table) field based on the code passed to it. So I want to test my filter functionality where we will Document type code and it shall return description. In case no description exists then ABAP Unit test shall fail.

Gateway Service created in SEGW with TVAKT table.


We used TVAKT table and created a service manually. Implemented the Get_Entityset method as shown below. The code simply returns the document type description based on the document type code passed to it.


METHOD tvaktset_get_entityset.
    DATA:lt_filters TYPE                   /iwbep/t_mgw_select_option,
         ls_filter  TYPE                   /iwbep/s_mgw_select_option,
         ls_val     TYPE /iwbep/s_cod_select_option.

    READ TABLE it_filter_select_options INTO ls_filter INDEX 1.
    IF sy-subrc EQ 0.
      READ TABLE ls_filter-select_options INTO ls_val INDEX 1.
      SELECT * FROM tvakt INTO TABLE et_entityset WHERE auart EQ ls_val-low AND spras = 'E'.
    ENDIF.
  ENDMETHOD.

ABAP Unit Test Class Definition


So we started by creating the unit test class for *DPC_EXT in the eclipse.

This class has 3 methods and 3 attributes

Attributes

1. CUT – referring to our DPC class
2. MS_REQUEST_CONTEXT_STRUCT requesting structure to get context object
3. MO_REQUEST_CONTEXT_OBJECT Object which will be passed to our DPC testing method.

Variable 2 and 3 were added after we faced an exception in our general flow explained below.

Methods

1. SETUP for our CUT object creation

2. GET_DOC_TYPE_TEXT for testing our different set of inputs.

3. RUN_FILTER basically contains reusable code to which test parameters are passed by GET_DOC_TYPE_TEXT method.

CLASS ltc_znabheet_dpc_ext DEFINITION FOR TESTING
RISK LEVEL HARMLESS
DURATION SHORT.
  PRIVATE SECTION.
    DATA:
      " Request Structure filled to get the corresponding request context.
      ms_request_context_struct TYPE /iwbep/cl_mgw_request_unittst=>ty_s_mgw_request_context_unit,
      " Request context which is normally passed to each method call
      mo_request_context_object TYPE REF TO /iwbep/cl_mgw_request_unittst,
      " DPC referring to our extension call
      cut                       TYPE REF TO zcl_znabheet_dpc_ext.
    METHODS setup.
    METHODS run_filter
      IMPORTING
        im_auart     TYPE string
        im_entity    TYPE string
        im_entityset TYPE string.
    METHODS get_doc_type_text FOR TESTING RAISING cx_static_check.

ENDCLASS.

ABAP Unit Test Class Implementation


In method GET_DOC_TYPE_TEXT we call our RUN_FILTER method for each pair of inputs.  In RUN_FILTER method we first tried to fill the Filter internal table and call GET_ENTITYSET method with just filter table with a hope that it will return us the searched values. Sadly it did not work, we were thrown an exception.

CLASS ltc_znabheet_dpc_ext IMPLEMENTATION.
  "Created our data provider
  METHOD setup.
    CREATE OBJECT cut.
  ENDMETHOD.
  METHOD get_doc_type_text.
    " Run valid Test
    run_filter( EXPORTING im_auart = 'AG' im_entity = 'TVAKT' im_entityset = 'TVAKTSet' ).
    " Run Invalid test
    "run_filter( EXPORTING im_auart = 'ZZ' im_entity = 'TVAKT' im_entityset = 'TVAKTSet').
  ENDMETHOD.


  METHOD run_filter.
    DATA: lt_filter_select_options TYPE /iwbep/t_mgw_select_option,
          ls_filter_select_option  TYPE /iwbep/s_mgw_select_option,
          lt_filter                TYPE /iwbep/t_cod_select_options,
          ls_filter                TYPE /iwbep/s_cod_select_option,
          lr_data                  TYPE REF TO data,
          ls_context               TYPE /iwbep/if_mgw_appl_srv_runtime=>ty_s_mgw_response_context.
    FIELD-SYMBOLS: <tab> TYPE table.

    " Fill the filter field detail
    ls_filter-sign = 'I'.
    ls_filter-option = 'EQ'.
    ls_filter-low = im_auart.
    APPEND ls_filter TO lt_filter.
    ls_filter_select_option-property = im_auart.
    ls_filter_select_option-select_options = lt_filter.
    APPEND ls_filter_select_option TO lt_filter_select_options.

    "read data
    TRY .
        cut->/iwbep/if_mgw_appl_srv_runtime~get_entityset(
          EXPORTING
            io_tech_request_context   = mo_request_context_object
            it_filter_select_options     = lt_filter_select_options    " Table of select options
          IMPORTING
            er_entityset              = lr_data
            es_response_context       = ls_context
        ).

      CATCH /iwbep/cx_mgw_busi_exception.

      CATCH /iwbep/cx_mgw_tech_exception.

    ENDTRY.
    " If no data found for document type text then it is an exception
    ASSIGN lr_data->* TO <tab>.
    CALL METHOD cl_abap_unit_assert=>assert_not_initial
      EXPORTING
        act = <tab>. " Actual Data Object
  ENDMETHOD.

ENDCLASS.


So that actually led us to something related to Request context parameter is missing.

ABAP Unit Test Class – Method INIT_DP_FOR_UNIT_TEST


SAP has provided a method named INIT_DP_FOR_UNIT_TEST in all DPC_EXT classes to support unit testing. This method initializes the data provider instance or request context which we will be using to pass to our service call.

We implemented this method before the service call and Bingo everything was working fine both for positive as well as negative test cases. Revised RUN_FILTER method.

METHOD run_filter.
    DATA: lt_filter_select_options TYPE /iwbep/t_mgw_select_option,
          ls_filter_select_option  TYPE /iwbep/s_mgw_select_option,
          lt_filter                TYPE /iwbep/t_cod_select_options,
          ls_filter                TYPE /iwbep/s_cod_select_option,
          lr_data                  TYPE REF TO data,
          ls_context               TYPE /iwbep/if_mgw_appl_srv_runtime=>ty_s_mgw_response_context.
    FIELD-SYMBOLS: <tab> TYPE table.
    " Fill the data set and entity names to be unit tested
    ms_request_context_struct-technical_request-source_entity_type = im_entity.
    ms_request_context_struct-technical_request-target_entity_type = im_entity.
    ms_request_context_struct-technical_request-source_entity_set = im_entityset.
    ms_request_context_struct-technical_request-target_entity_set = im_entityset.

    " Fill the filter field detail
    ls_filter-sign = 'I'.
    ls_filter-option = 'EQ'.
    ls_filter-low = im_auart.
    APPEND ls_filter TO lt_filter.
    ls_filter_select_option-property = im_auart.
    ls_filter_select_option-select_options = lt_filter.
    APPEND ls_filter_select_option TO lt_filter_select_options.

    " Every DPC class now has INIT_DP_FOR_UNIT_TEST method which is used to provide a data
    " instance which can be used for unit testing
    mo_request_context_object =  cut->/iwbep/if_mgw_conv_srv_runtime~init_dp_for_unit_test(
     is_request_context = ms_request_context_struct
     ).
    "read data
    TRY .
        cut->/iwbep/if_mgw_appl_srv_runtime~get_entityset(
          EXPORTING
            io_tech_request_context   = mo_request_context_object
            it_filter_select_options     = lt_filter_select_options    " Table of select options
          IMPORTING
            er_entityset              = lr_data
            es_response_context       = ls_context
        ).

      CATCH /iwbep/cx_mgw_busi_exception.

      CATCH /iwbep/cx_mgw_tech_exception.

    ENDTRY.
    " If no data found for document type text then it is an exception
    ASSIGN lr_data->* TO <tab>.
    CALL METHOD cl_abap_unit_assert=>assert_not_initial
      EXPORTING
        act = <tab>. " Actual Data Object
  ENDMETHOD.


Learning


In order to implement ABAP unit test, method INIT_DP_FOR_UNIT_TEST must be called to get the request context.

No comments:

Post a Comment