This is a test message to test the length of the message box.
Login
ABAP Unit Test OData
Created by Software-Heroes

ABAP Unit - Test OData

1327

This article is about the testability of OData Services and how you can use it to test interfaces quickly and easily.



In this article we will look at testing an OData service in two ways. Once via the classic route with a data provider class and once via the new route of a service via RAP.

 

Data-Provider class

General

In order to be able to test a data provider class, we must first create an instance of the class and an instance of the context object in order to be able to test the method properly at all. A few additional steps are necessary for this so that we can test the provider properly. In the first step, we want to bring you closer to the test case.

In our test we would like to provide an OData service for the following table that provides the typical CRUD operations. The table is populated with all possible demo fields:

 

We create a service using transaction SEGW and import the table as a structure. The system will suggest the names of the fields accordingly. We call the entity “DATA” for the sake of simplicity.

 

The complete implementation of the DPC class ZCL_TEST_UNITTEST_DPC_EXT can be found in the corresponding examples at the end of the book. Now the following test class to implement the test case for creating and reading.

CLASS ltc_odata DEFINITION FINAL FOR TESTING
  DURATION SHORT
  RISK LEVEL HARMLESS.

  PRIVATE SECTION.
    DATA:
      mo_cut                    TYPE REF TO zcl_test_unittest_dpc_ext,
      mo_request_context_object TYPE REF TO /iwbep/cl_mgw_request_unittst.

    METHODS:
      read_data FOR TESTING RAISING cx_static_check,
      create_data FOR TESTING RAISING cx_static_check,

      prepare_cut.
ENDCLASS.


CLASS ltc_odata IMPLEMENTATION.
  METHOD prepare_cut.
    mo_cut = NEW zcl_test_unittest_dpc_ext( ).

    DATA(ls_request_context) = VALUE /iwbep/cl_mgw_request_unittst=>ty_s_mgw_request_context_unit(
      technical_request = VALUE #(
        source_entity_set     = 'DATASet'
        target_entity_set     = 'DATASet'
        source_entity_type    = 'DATA'
        target_entity_type    = 'DATA'
      )
    ).

    mo_request_context_object = mo_cut->/iwbep/if_mgw_conv_srv_runtime~init_dp_for_unit_test( ls_request_context ).
  ENDMETHOD.


  METHOD read_data.
    DATA:
      lt_data TYPE STANDARD TABLE OF zbs_test_data.

    prepare_cut( ).

    DATA(lt_filter) = VALUE /iwbep/t_mgw_select_option(
      ( 
        property = 'CURRENCY' 
        select_options = VALUE #( ( sign = 'I' option = 'EQ' low = 'CHF' ) ) 
      )
    ).

    mo_cut->/iwbep/if_mgw_appl_srv_runtime~get_entityset(
      EXPORTING
        io_tech_request_context  = mo_request_context_object
        it_filter_select_options = lt_filter
      IMPORTING
        er_entityset             = DATA(lr_entity)
        es_response_context      = DATA(ls_response_context)
    ).

    ASSIGN lr_entity->* TO FIELD-SYMBOL(<lt_data>).
    lt_data = CORRESPONDING #( <lt_data> ).

    cl_abap_unit_assert=>assert_equals( act = lines( lt_data ) exp = 2 ).
  ENDMETHOD.


  METHOD create_data.
    DATA:
      ls_new TYPE zbs_test_data.

    prepare_cut( ).

    DATA(ls_new_data) = VALUE zbs_test_data(
      description   = 'A set of testdata from UNIT Test'
      amount        = '12.50'
      currency      = 'USD'
      creation_user = sy-uname
      creation_time = sy-uzeit
      creation_data = sy-datum
    ).
    DATA(lo_data_provider) = NEW /iwbep/cl_cp_v2_entry_provider( REF #( ls_new_data ) ).

    mo_cut->/iwbep/if_mgw_appl_srv_runtime~create_entity(
      EXPORTING
        io_data_provider        = lo_data_provider
        io_tech_request_context = mo_request_context_object
      IMPORTING
        er_entity               = DATA(lr_entity)
    ).

    ASSIGN lr_entity->* TO FIELD-SYMBOL(<ls_data>).
    ls_new = CORRESPONDING #( <ls_data> ).

    cl_abap_unit_assert=>assert_not_initial( ls_new-identifier ).
  ENDMETHOD.
ENDCLASS.

 

Procedure

What about the actual test case and the execution? To set up the test instance, a few steps must be carried out beforehand, as we also need a context object in order to be able to execute the methods.

  • Preparation
    • Fill the context structure with the entity to be tested and the name of the set
    • Call the init method of the service runtime
    • Save the context object in the test class
  • Reading data
    • Definition of a filter to restrict the data sets
    • Call of method GET_ENTITYSET with context object and additional data (filter)
    • Examination of the data records found for the test
  • Creating data
    • Preparation of a new data set
    • Creation of a data provider object with the data as a reference
    • Call of method CREATE_ENTITY with context object and data provider
    • Checking the new key for the test

 

Hint: We only partially recommend testing OData Services using this method, as the methodology does not support the full range of functions of the services. If possible, testing with service bindings should be used.

 

Service Binding

The service binding is the latest variant of providing an OData from the implementation of a business object via RAP. Eclipse provides a wizard that implements the coding in its own test class or you write your own tests. We don't want to show you at this point how you can build your own business object using RAP, but how you can create one from the finished service, generate test class and then test it. RAP by itself, would fill half a book again.

 

Preparation

In order to be able to create the test class automatically via the wizard, you have to open the service binding of the data model for which you want to define your test cases. The object creates the corresponding endpoint and the protocol (in this case OData v2) for a service.

 

With a right click on the corresponding entity you can then generate a test class via the context menu.

 

In the wizard you only have to enter the package and the name of the test class, the rest is automatically pre-assigned. At the end a global test class is created, while the actual test cases are again in the local test classes of this class.

 

Example

As with the other OData service, we will implement the example for you for reading data records and creating a new data record. The handling of the local proxy is a lot easier than working with the DPC class. For the proxy there is a version for on-premise and one for the BTP, depending on the environment you are in.

CLASS ltc_odata_service DEFINITION FINAL FOR TESTING
  DURATION SHORT
  RISK LEVEL HARMLESS.

  PRIVATE SECTION.
    DATA:
      mo_client_proxy TYPE REF TO /iwbep/if_cp_client_proxy.

    METHODS:
      setup RAISING cx_static_check,

      create_data FOR TESTING RAISING cx_static_check,
      read_data FOR TESTING RAISING cx_static_check.
ENDCLASS.

CLASS ltc_odata_service IMPLEMENTATION.
  METHOD setup.
    " On-Premise Proxy
    mo_client_proxy = /iwbep/cl_cp_client_proxy_fact=>create_v2_local_proxy(
      VALUE #( service_id = 'ZBS_UI_DEMOSIMPLERAP_O2' service_version = '0001' )
    ).

    " BTP Proxy
*    mo_client_proxy = cl_web_odata_client_factory=>create_v2_local_proxy(
*      VALUE #( service_id = 'ZBS_UI_DEMOSIMPLERAP_O2' service_version = '0001' )
*    ).
  ENDMETHOD.


  METHOD create_data.
    DATA:
      ls_business_data TYPE ZBS_C_DemoSimpleRAP,
      lo_request       TYPE REF TO /iwbep/if_cp_request_create,
      lo_response      TYPE REF TO /iwbep/if_cp_response_create.

    ls_business_data = VALUE #(
      Item        = 'HAMMER'
      Description = 'A good tool for nails'
      ItemNumber  = 4911
    ).

    lo_request = mo_client_proxy->create_resource_for_entity_set( 'SimpleRap' )->create_request_for_create( ).
    lo_request->set_business_data( ls_business_data ).
    lo_response = lo_request->execute( ).

    CLEAR ls_business_data.
    lo_response->get_business_data( IMPORTING es_business_data = ls_business_data ).

    cl_abap_unit_assert=>assert_not_initial( ls_business_data-UniqueKey ).
  ENDMETHOD.


  METHOD read_data.
    DATA:
      lt_business_data  TYPE TABLE OF ZBS_C_DemoSimpleRAP,
      lo_request        TYPE REF TO /iwbep/if_cp_request_read_list,
      lo_response       TYPE REF TO /iwbep/if_cp_response_read_lst,
      lo_filter_factory TYPE REF TO /iwbep/if_cp_filter_factory,
      lt_r_number       TYPE RANGE OF ZBS_C_DemoSimpleRAP-ItemNumber.

    lo_request = mo_client_proxy->create_resource_for_entity_set( 'SimpleRap' )->create_request_for_read( ).

    lt_r_number = VALUE #( ( sign = 'I' option = 'EQ' low = 2 ) ).

    lo_filter_factory = lo_request->create_filter_factory( ).
    DATA(lo_filter_node) = lo_filter_factory->create_by_range(
      iv_property_path     = 'ITEMNUMBER'
      it_range             = lt_r_number ).
    lo_request->set_filter( lo_filter_node ).

    lo_request->set_top( 50 )->set_skip( 0 ).
    lo_response = lo_request->execute( ).

    lo_response->get_business_data( IMPORTING et_business_data = lt_business_data ).

    cl_abap_unit_assert=>assert_equals( act = lines( lt_business_data ) exp = 2 ).
  ENDMETHOD.
ENDCLASS.

 

We use the Consumption View (Core Data Service) to assign the data, as the corresponding field names for the OData Service are provided here and other field names could apply to the database.

 

Procedure

The corresponding process in the test class is briefly explained again:

  • Preparation
    • Creation of the local proxy object for the connection to the service
  • Reading data
    • Generating the request object for reading
    • Setting the filter and TOP/SKIP values
    • Execution of the request
    • Reading the data from the response object
  • Creating data
    • Creation of the new data record
    • Generation of the request object for the system 
    • Transfer of the data
    • Execution of the request
    • Evaluation of the answer (filling of the key)

 

Test Double

Don't want to test against the real data in the database? Then you can also use a test double for the core data service that is addressed. The SQL double for the table will not work here.

To do this, simply prepare and activate the corresponding double in the setup method. The accesses via the proxy then run against the CDS double.

 

Conclusion

OData services can be tested and checked just like other objects, which should make your development more stable in the future. The provision and further development of such services will make up a large part of the resources that are required in the backend in the future.


Included topics:
ABAP UnitABAPUnit TestsTest OData
Comments (0)



And further ...

Are you satisfied with the content of the article? We post new content in the ABAP area every Friday and irregularly in all other areas. Take a look at our tools and apps, we provide them free of charge.


ABAP Unit - Test execution

Category - ABAP

What options are there for executing ABAP Unit and what hidden functions might you not know about? More details about the different modes in this article.

06/25/2024

ABAP Unit - Automation

Category - ABAP

When do objects break during development and what side effects can adjustments have? In this article we take a closer look at the topic.

01/05/2024

ABAP Unit - TDF (Function Double)

Category - ABAP

In this article, let's take a look at how we can deal with function modules as dependencies without testing them as well.

04/07/2023

RAP - ABAP Unit (Service)

Category - ABAP

How do you actually test the service of an interface or RAP app automatically? In this article we look at unit tests for OData services.

01/20/2023

RAP - ABAP Unit (Business Object)

Category - ABAP

At this point, we'll take a look at how we can test our RAP Business Object automatically in order to check all important functions at the touch of a button.

01/13/2023