Skip to Content
Technical Articles
Author's profile photo Adam Krawczyk

ABAP Unit Tests for ODATA requests


Welcome to my blog, I am glad that you are curious about ABAP unit testing. Let’s go.

As an SAP developer coming from the Java world, I always focus on Object Oriented ABAP and believe in the high value of unit testing. So the question came once, how should I test ODATA service?

In the past I tried to build mocking classes, so that I could call the ZCL*DPC_EXT methods, but it was too difficult and had little value when compared to development efforts. Then I left the topic and decided to keep example requests in SAP Gateway Client through transaction /IWFND/GW_CLIENT. That was ok for documenting purposes, but it was not a unit test unfortunatelly.

ABAP Unit Tests for ODATA

Custom utility method for ODATA request

For me it was not ok to deploy ODATA service without unit testing. I was creating tests for business logic, but why not to verify ODATA requests within seconds? I did research and found this blog which inspired me a lot, thanks to the author:

It is a clear recipe for how to test ODATA service and it works. But it was not suitable for me as I wanted to test different filters, expand, select options easily.

So again I did homework, debugged how SAP is running Gateway Client and built a simple utility method. It uses standard SAP methods. Few lines of code allows testing ODATA requests by exact string, like the client would call it. I think this is a simple but powerful way of testing requests, as we want to keep the syntax stable, especially when API was shared with client applications:

  • It gives control and verifies that for a given request we get expected results and the API is stable.
  • It quickly discovers if someone has changed parameter / entity name, so that it could have side effects for existing client applications. And if that is an expected change then unit tests must be also adjusted.
  • It is a good documentation of how you can call the service and what are most common requests/use cases.

I am sharing the code which does the magic. I hope that at least one of you will take a chance to create automated unit tests for ODATA service by importing this code into your system.

CLASS-METHODS call_odata_request_json_format
          add_server_url       type abap_bool default abap_true
          odata_url            TYPE string
          VALUE(json_data)     TYPE any
          response_full_string TYPE string.

METHOD call_odata_request_json_format.

  CLEAR: json_data, response_full_string.

  DATA(final_odata_url) = odata_url.

  IF NOT ( final_odata_url CS '$format=json' ).
    IF ( final_odata_url CS '?' ).
      final_odata_url = final_odata_url && '&$format=json'.
      final_odata_url = final_odata_url && '?$format=json'.

  DATA(request_header) = VALUE /iwfnd/sutil_property_t(
          ( VALUE #( name = '~request_method' value = 'GET' ) )
          ( VALUE #( name = '~request_uri' value = final_odata_url ) )

    DATA(http_caller) = /iwfnd/cl_sutil_client_proxy=>get_instance( ).

        it_request_header     = request_header                 " HTTP Request Header - Table
        ev_status_code        = DATA(resp_status_code)         " HTTP Status Code
        ev_status_text        = DATA(resp_status_text)         " HTTP Status Text
        et_response_header    = DATA(resp_header)              " HTTP Response Header - Table
        ev_response_body      = DATA(resp_body)                " HTTP Response Body

    response_full_string = /iwfnd/cl_sutil_xml_helper=>transform_to_string( resp_body ).

        jsonx            = resp_body                 " JSON XString
        data             = json_data                " Data to serialize



Does it look complex? Maybe. But later you will see how easy it is to call it in a test code. Let’s explain sections quickly:

  • Initially we verify if the query contains $format=json and if not we add it. We want to force json format so that result can be easily formatted to structure.
  • request_header uses a specific format to pass the URL into web_request later. The URL can be relative, starting with /sap/opu/odata.
  • web_request method is the core method that makes the ODATA request. More parameters can be added, but in my example the basic ones are imported.
  • transform_to_string method converts bytes from response into readable text, containting the response content.
  • /ui2/cl_json=>deserialize is used to parse the response JSON string into the structure. If the structure has matching fields to JSON structure, data is automatically populated. Note that parameter type is any so it is up to the calling program to pass the relevant type.

Creating unit test for ODATA request

Now it is time to see how the utility method can be used for test. I put it into ZCL_UTILS_UI5 class as a static method. Let’s assume that we have a model with a MaterialSet entity and $expand navigation to_ChangeLog, which allows us to retrieve ChangeLog data on demand.

METHOD test_odata_request.

    " Example of material entity type definition for json data mapping, entity found by key
    TYPES BEGIN OF type_json_resp_material.
    INCLUDE TYPE zcl_material_mpc=>ts_zmaterial_ctype.
    " Now example of expand entity
    types to_changelog type zcl_material_mpc=>ts_zmaterial_change_record.
    TYPES  END OF type_json_resp_material.

    " Example of material list type definition for json data mapping, entities found by filter
    TYPES BEGIN OF type_json_resp_material_list.
    TYPES results TYPE STANDARD TABLE OF zcl_material_mpc=>ts_zmaterial_ctype WITH DEFAULT KEY.
    TYPES  END OF type_json_resp_material_list.

    DATA json_response_entity TYPE type_json_resp_material.
    DATA json_response_list TYPE type_json_resp_material_list.

    DATA(odata_url) = |/sap/opu/odata/SAP/ZMATERIAL_SRV/MaterialSet('00000001')|.

        odata_url            = odata_url
        json_data            = json_response_entity
        response_full_string = DATA(response_string)

        act = json_response_entity-d-materialnumber
        exp = '00000001'
        msg = 'Material number not retrieved from ODATA request as expected'

    odata_url = odata_url && '?$format=json&$expand=to_ChangeLog'.

        odata_url            = odata_url
        json_data            = json_response_entity
        response_full_string = DATA(response_string2)

        act = json_response_entity-d-materialnumber
        exp = '00000001'
        msg = 'Adding $format=json should have same effect, as it is defaulted'

        act = json_response_entity-d-to_changelog-materialnumber
        exp = '00000001'
        msg = 'Expand to_ChangeLog should also fill in subentity data'

Example above shows just the simple calls, but it can be easily extended with any ODATA query.

Many lines of code above are used for types definitions and we use MPC class for simplification. This is because we want to have data mapped automatically by the JSON framework into corresponding fields of structure. Then it is easy to do response data verification.

As an alternative we can also process the response_string which is a JSON formatted text response, useful for debugging where we see the conents of the ODATA response.

Additional notes

  • Any ODATA $parameters can be easily added for test, like $filter, $expand, $skip, $filter – no limitation, simply define your query as you want it.
  • Local types definitions can be set up just once on top of Unit Test class, so that it is reused across test methods.
  • I think that unit tests can be created in DPC_EXT class as relevant to the ODATA service, or else a new custom business class can be used.
  • Note that this is testing on a live database in development system and data can be changed in the future. Make sure that data exists in tables before you do assertion on ODATA response results!


Now I can verify my ODATA service with different variants in 2.6 seconds:


There are many explanations why not to create Unit Tests. But if you create them, all in all there will be isolated areas of tested code which at the end become bigger tested areas.

SAP ODATA automated testing was too difficult for me to practice it. Now with the simple framework I can do it with little effort. I believe that these tests will be a good documentation and I try to test at least scenarios which are used by client applications.

Finally the power of unit tests is that they verify functionality within seconds and can be scheduled automatically if needed. If we practice them, they do not add time but make development faster, there are less defects in quality.

Thank you for your time and good luck with coding!


Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Ralph Sullivan
      Ralph Sullivan

      Thanks for sharing this, Adam. The elements in my model structures don't match my entity property names, so I had to create detailed types with the correct names. After doing that, it works like a charm!

      Author's profile photo Adam Krawczyk
      Adam Krawczyk
      Blog Post Author

      Great to hear that Ralph Sullivan. Now after you have created first working test, building new ODATA testcases will be just simple. And practicing unit tests is a code craftsmanship, congratulations!

      Author's profile photo Subba Krishna
      Subba Krishna

      Hello Adam,

      great blog!!Thanks a is really helpful...can you also show how the below method is called from main program.





      Author's profile photo Adam Krawczyk
      Adam Krawczyk
      Blog Post Author

      Hi Subba Krishna ,

      Thank you!

      The method test_odata_request is part of ABAP Unit Test, so it is automatically called by test environment. So it is not called by any production code / main program.


      Author's profile photo Krzysztof Żak
      Krzysztof Żak

      Thank you, it works like a charm!

      In my case, I just had to add one parameter to /ui2/cl_json=>deserialize call

      jsonx = resp_body " JSON XString
      pretty_name = /ui2/cl_json=>pretty_mode-camel_case
      data = json_data " Data to serialize