Wednesday 22 February 2023

TDD: Use GitHub as data storage for your test data.

Usually, you can find plenty of articles and blogs about the TDD and how to write or use TDD approach in your project development. But this blog is not about it.

Well actually it is, but here I want to grab your attention to the other side of the coin. Namely, to have dynamic data storage to save your test data and to test your coding with plenty of cases. Besides, not only developers but also functional people can use it without any difficulty.

Well, I guess sounds interesting, then let’s start step by step.

Introduction


First thing is first, let’s have a small introduction what’s TDD and why we need to use it.

Test-driven development (TDD for short) is a programming approach in which developers write production code in response to a test case, as opposed to the traditional process where code is written first, and relevant test cases are created later.

In other words, in TDD, tests guide the implementation. This results in easier to maintain and better-quality code, but at the same time, increases the initial development time which is main cause of having a lot of debates like “To use or Not to use, That’s a question”

TDD is an effective specification technique that also ensures effective unit testing and results through 100% test coverage which means you can test all parts of your code. However, it doesn’t fully replace traditional testing. Well, why?

Because as developer you may not see all the cases that functional people can find later during testing.

For example, TDD contains three main parts as:

◉ Given – to define data to be tested.
◉ When – Call to the method which is to be checked.
◉ Then – Comparing the actual and expected result from when section.

In this blog, I will more focus on the Given section (personally that’s time-consuming part for me) how can developer look to the coding with the eyes of functional people

Problem


Imagine that you are in team which is having project to create custom Fiori app and app works mainly with purchase order and sales order. So, app should create/update/delete Purchase Order. Usually, you can do it with one BAPI BAPI_PO_CREATE1.

But the point is, there can be a lot of cases to check: create Simple PO with one item, create PO with multiple items, create PO with schedule lines, with only header text data, with both header and item text data, create PO with account assignments and to go through all these cases you need different test data each time, and not mentioning this is only Create case

Solution


So, I used GitHub and saved all test data there in my public repository, by this not only me, but also functional people in my team can add new test data and easily check result.

For this purpose, I have created one repository in my GitHub profile, and I created folder for all CRUD operations. Here is the structure of it.

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP Prep, SAP ABAP Preparation, SAP ABAP Learning

Any team member who wants to test my coding can create his/her own test data in appropriate folder and simply choose test data in the report (later we will create it), execute and see the result.

Another important thing is how to get payload from GitHub and how to correctly organize the path. In order to get data, I will use API GitHub. Actually, it helps you to get your payload without any extra HTML tags. For more information, please go to the official documentation.


We can have a look to the contents of my repository by simply applying:

GitHub profile name + repository name + ‘/contents’ –  https://api.github.com/repos/akmal-kilichbekov/TTDBlog/contents

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP Prep, SAP ABAP Preparation, SAP ABAP Learning

We need the highlighted URL to execute HTTP request in ABAP report to get file content in JSON file.

Now we will create report that is used to execute our test classes with a test data. It is just simple report and I added parameters to add folder and test file name.

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP Prep, SAP ABAP Preparation, SAP ABAP Learning

We are approaching interesting part, that’s how to use payload and set unit test class to the listeners.

Now let’s start by creating the report logic to get test data contents from GitHub. So here is my source code in the above report:

DATA lv_url TYPE char255.
DATA lo_http_helper TYPE REF TO zcl_akb_tdd_blog.

CONSTANTS: cv_apigithub_url TYPE string VALUE 'https://api.github.com/repos/',
           cv_apigithub_sfx TYPE string VALUE '?ref=main',
           cv_apigithub_content TYPE string VALUE '/contents/'.

SELECTION-SCREEN: BEGIN OF BLOCK b2 WITH FRAME TITLE TEXT-002.
  PARAMETERS p_accnt TYPE char30 LOWER CASE DEFAULT 'akmal-kilichbekov'.
  PARAMETERS p_repos TYPE char30 LOWER CASE DEFAULT 'TTDBlog'.
  PARAMETERS p_folder TYPE char20 LOWER CASE DEFAULT 'Create'.
SELECTION-SCREEN : END OF BLOCK b2.

lv_url = |{ cv_apigithub_url }{ p_accnt }/{ p_repos }/contents/{ p_folder }/{ cv_apigithub_sfx }|.

lo_http_helper = NEW #( ).
lo_http_helper->execute_http_request( lv_url ).

As you see the main functionality here is to get the values to form URL and call a helper class to execute the HTTP request.

Now let’s see the logic inside the class:

METHOD execute_http_request.
  DATA lt_git_file TYPE STANDARD TABLE OF ty_pfiles.
  DATA lt_deserialized_files TYPE tt_git_file.

  " Deserialize the response
  /ui2/cl_json=>deserialize( EXPORTING json        = call_web_request( iv_url )
                                       pretty_name = /ui2/cl_json=>pretty_mode-camel_case
                             CHANGING  data        = lt_deserialized_files ).

  " Map to normal internal table
  lt_git_file = CORRESPONDING #( lt_deserialized_files MAPPING filename = name
                                                               filepath = download_url ).

  " Get the all files content in chosen folder
  LOOP AT lt_git_file ASSIGNING FIELD-SYMBOL(<fs_git_file>).
    DATA(lv_response_data) = call_web_request( <fs_git_file>-filepath  ).

    " Remove PO number
    FIND FIRST OCCURRENCE OF '{' IN lv_response_data MATCH OFFSET DATA(lv_index).

    lv_response_data = substring( val = lv_response_data off = lv_index 
                                  len = strlen( lv_response_data ) - lv_index ).

    mt_files = VALUE #( BASE mt_files ( file_name    = <fs_git_file>-filename 
                                        file_content = lv_response_data ) ).
  ENDLOOP.

ENDMETHOD.
 
Usually method performs two HTTP GET request:

1. To get content inside the folder – all test files inside Create folder in my case
2. To get content of each test file – that’s done inside the LOOP statement.

Since both above actions are the same from technical point of view, I added one general method to execute HTTP GET request – call_web_request

METHOD call_web_request.
  DATA lt_request_header TYPE /iwfnd/sutil_property_t.

  " Get client proxy class instance
  DATA(lo_http_prx) = /iwfnd/cl_sutil_client_proxy=>get_instance( ).

  " Prepare header data
  lt_request_header = VALUE #( ( name = if_http_header_fields_sap=>request_method value = 'GET' )
                               ( name = '~request_uri'  value = iv_url )
                               ( name = 'accept'        value = 'application/json' ) ).

  " Execute HTTP request
  lo_http_prx->web_request( EXPORTING it_request_header   = lt_request_header
                                      iv_reuse_connection = abap_true
                            IMPORTING ev_status_code      = DATA(ev_status_code)
                                      ev_content_type     = DATA(lv_content_type)
                                      et_response_header  = DATA(lt_response_header)
                                      ev_response_body    = DATA(lv_response_body) ).

  " Get the response
  rv_response = cl_abap_codepage=>convert_from( source = lv_response_body ).
ENDMETHOD.

So if we have a look to the logic via the debugger, we can surely see that

1. Gets content inside the folder – first call to the method call_web_request

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP Prep, SAP ABAP Preparation, SAP ABAP Learning

2. Gets file content in predefined folder

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP Prep, SAP ABAP Preparation, SAP ABAP Learning

No comments:

Post a Comment