This is a test message to test the length of the message box.
Login
ABAP in Practice Test Driven Development
Created by Software-Heroes

ABAP in Practice - Test Driven Development

659

How does TDD actually work in practice and are there simple examples for learning in ABAP? In this exercise we will look at the practical part.



In this article we will look at a practical and playful example of implementing test-driven development and how you could use it in your work.

 

Introduction

Before the actual development, we first want to implement our unit tests and see that they are running on "red". We will then start implementing the actual logic and bring the unit tests into the "green" state. With the tests, we first want to cover all use cases and requirements in order to then develop the solution. This development methodology is particularly difficult to implement because we as developers have to think about what we need beforehand. This also allows us to achieve three goals:

  • The unit tests work (red -> green)
  • Our code is written in a testable manner
  • Unit tests are available

 

If you want to learn more about TDD, you can find a good article on Wikipedia.

 

Preparation

In this task, we want to create a converter for Roman numerals to convert the numbers in both directions. To do this, we need a class that has two methods for the conversion. We can then implement it based on this. In this example, we reuse an Exception class to catch special cases in the methods.

CLASS zcl_bs_demo_roman_numbers DEFINITION
  PUBLIC FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    METHODS convert_roman_to_arabic
      IMPORTING id_roman         TYPE string
      RETURNING VALUE(rd_result) TYPE i
      RAISING   cx_abap_not_in_allowlist.

    METHODS convert_arabic_to_roman
      IMPORTING id_arabic        TYPE i
      RETURNING VALUE(rd_result) TYPE string
      RAISING   cx_abap_not_in_allowlist.
      
  PRIVATE SECTION.
ENDCLASS.


CLASS zcl_bs_demo_roman_numbers IMPLEMENTATION.
  METHOD convert_arabic_to_roman.
  ENDMETHOD.


  METHOD convert_roman_to_arabic.
  ENDMETHOD.
ENDCLASS.

 

Task

The task now is to implement the class using Test Driven Development. In the first step, we want to implement the unit tests in order to then develop the logic piece by piece and get to know the advantages of TDD. The following rules apply for the conversion:

  • There are the following Roman numerals...
    • I - 1
    • V - 5
    • X - 10
    • L - 50
    • C - 100
    • D - 500
    • M - 1000
  • A maximum of three identical characters in a row, with V/L/D standing alone.
  • Subtraction rule - If a smaller number is in front of a larger number, the smaller is subtracted from the larger ones are subtracted.
  • Range - The smallest Roman number is 1 and the largest is 3999 without breaking the rules.

 

Hint: In the next section we will go into the solution, if you want to do the task on your own, you should pause here.

 

Solution

In this section we go through the solution piece by piece and implement the various Components.

 

Unit Tests

So let's start with our unit tests in the first step. To do this, we implement a first test class that deals with converting Roman numbers into Arabic numbers. For the other method, we would create a second test class accordingly.

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

  PRIVATE SECTION.
    DATA mo_cut TYPE REF TO zcl_bs_demo_roman_numbers.

    METHODS setup.

    METHODS convert_i FOR TESTING.
ENDCLASS.


CLASS ltc_roman_to_arabic IMPLEMENTATION.
  METHOD setup.
    mo_cut = NEW #( ).
  ENDMETHOD.


  METHOD convert_i.
    DATA(ld_result) = mo_cut->convert_roman_to_arabic( `I` ).

    cl_abap_unit_assert=>assert_equals( exp = 1
                                        act = ld_result ).
  ENDMETHOD.
ENDCLASS.

 

Using the setup method, we can always create a new and clean instance of MO_CUT (Class/Code under Test) and do not have to implement the code in every test method. Accordingly, we would now test various combinations and special cases. We should also catch the error cases and pass numbers that are too large, or not pass them at all.

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

  PRIVATE SECTION.
    DATA mo_cut TYPE REF TO zcl_bs_demo_roman_numbers.

    METHODS setup.

    METHODS convert_i         FOR TESTING RAISING cx_static_check.
    METHODS convert_iii       FOR TESTING RAISING cx_static_check.
    METHODS convert_iv        FOR TESTING RAISING cx_static_check.
    METHODS convert_v         FOR TESTING RAISING cx_static_check.
    METHODS convert_ix        FOR TESTING RAISING cx_static_check.
    METHODS convert_lxviii    FOR TESTING RAISING cx_static_check.
    METHODS convert_cccxlix   FOR TESTING RAISING cx_static_check.
    METHODS convert_mccxxxiv  FOR TESTING RAISING cx_static_check.
    METHODS convert_mmmcmxcix FOR TESTING RAISING cx_static_check.
    METHODS convert_unknown   FOR TESTING RAISING cx_static_check.
    METHODS convert_empty     FOR TESTING RAISING cx_static_check.
ENDCLASS.


CLASS ltc_roman_to_arabic IMPLEMENTATION.
  METHOD setup.
    mo_cut = NEW #( ).
  ENDMETHOD.


  METHOD convert_i.
    DATA(ld_result) = mo_cut->convert_roman_to_arabic( `I` ).

    cl_abap_unit_assert=>assert_equals( exp = 1
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_cccxlix.
    DATA(ld_result) = mo_cut->convert_roman_to_arabic( `CCCXLIX` ).

    cl_abap_unit_assert=>assert_equals( exp = 349
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_empty.
    TRY.
        mo_cut->convert_roman_to_arabic( `` ).

        cl_abap_unit_assert=>fail( 'Error should occure' ).

      CATCH cx_abap_not_in_allowlist.
    ENDTRY.
  ENDMETHOD.


  METHOD convert_iii.
    DATA(ld_result) = mo_cut->convert_roman_to_arabic( `III` ).

    cl_abap_unit_assert=>assert_equals( exp = 3
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_iv.
    DATA(ld_result) = mo_cut->convert_roman_to_arabic( `IV` ).

    cl_abap_unit_assert=>assert_equals( exp = 4
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_ix.
    DATA(ld_result) = mo_cut->convert_roman_to_arabic( `IX` ).

    cl_abap_unit_assert=>assert_equals( exp = 9
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_lxviii.
    DATA(ld_result) = mo_cut->convert_roman_to_arabic( `LXVIII` ).

    cl_abap_unit_assert=>assert_equals( exp = 68
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_mccxxxiv.
    DATA(ld_result) = mo_cut->convert_roman_to_arabic( `MCCXXXIV` ).

    cl_abap_unit_assert=>assert_equals( exp = 1234
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_mmmcmxcix.
    DATA(ld_result) = mo_cut->convert_roman_to_arabic( `MMMCMXCIX` ).

    cl_abap_unit_assert=>assert_equals( exp = 3999
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_unknown.
    TRY.
        mo_cut->convert_roman_to_arabic( `IIP` ).

        cl_abap_unit_assert=>fail( 'Error should occure' ).

      CATCH cx_abap_not_in_allowlist.
    ENDTRY.
  ENDMETHOD.


  METHOD convert_v.
    DATA(ld_result) = mo_cut->convert_roman_to_arabic( `V` ).

    cl_abap_unit_assert=>assert_equals( exp = 5
                                        act = ld_result ).
  ENDMETHOD.
ENDCLASS.


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

  PRIVATE SECTION.
    DATA mo_cut TYPE REF TO zcl_bs_demo_roman_numbers.

    METHODS setup.

    METHODS convert_0    FOR TESTING RAISING cx_static_check.
    METHODS convert_4000 FOR TESTING RAISING cx_static_check.
    METHODS convert_1    FOR TESTING RAISING cx_static_check.
    METHODS convert_3    FOR TESTING RAISING cx_static_check.
    METHODS convert_4    FOR TESTING RAISING cx_static_check.
    METHODS convert_9    FOR TESTING RAISING cx_static_check.
    METHODS convert_15   FOR TESTING RAISING cx_static_check.
    METHODS convert_587  FOR TESTING RAISING cx_static_check.
    METHODS convert_611  FOR TESTING RAISING cx_static_check.
    METHODS convert_789  FOR TESTING RAISING cx_static_check.
    METHODS convert_999  FOR TESTING RAISING cx_static_check.
    METHODS convert_1245 FOR TESTING RAISING cx_static_check.
    METHODS convert_3299 FOR TESTING RAISING cx_static_check.
    METHODS convert_3999 FOR TESTING RAISING cx_static_check.
ENDCLASS.


CLASS ltc_arabic_to_roman IMPLEMENTATION.
  METHOD setup.
    mo_cut = NEW #( ).
  ENDMETHOD.


  METHOD convert_0.
    TRY.
        mo_cut->convert_arabic_to_roman( 0 ).

        cl_abap_unit_assert=>fail( 'Error should occure' ).

      CATCH cx_abap_not_in_allowlist.
    ENDTRY.
  ENDMETHOD.


  METHOD convert_1.
    DATA(ld_result) = mo_cut->convert_arabic_to_roman( 1 ).

    cl_abap_unit_assert=>assert_equals( exp = `I`
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_1245.
    DATA(ld_result) = mo_cut->convert_arabic_to_roman( 1245 ).

    cl_abap_unit_assert=>assert_equals( exp = `MCCXLV`
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_15.
    DATA(ld_result) = mo_cut->convert_arabic_to_roman( 15 ).

    cl_abap_unit_assert=>assert_equals( exp = `XV`
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_3.
    DATA(ld_result) = mo_cut->convert_arabic_to_roman( 3 ).

    cl_abap_unit_assert=>assert_equals( exp = `III`
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_3299.
    DATA(ld_result) = mo_cut->convert_arabic_to_roman( 3299 ).

    cl_abap_unit_assert=>assert_equals( exp = `MMMCCXCIX`
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_3999.
    DATA(ld_result) = mo_cut->convert_arabic_to_roman( 3999 ).

    cl_abap_unit_assert=>assert_equals( exp = `MMMCMXCIX`
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_4.
    DATA(ld_result) = mo_cut->convert_arabic_to_roman( 4 ).

    cl_abap_unit_assert=>assert_equals( exp = `IV`
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_4000.
    TRY.
        mo_cut->convert_arabic_to_roman( 4000 ).

        cl_abap_unit_assert=>fail( 'Error should occure' ).

      CATCH cx_abap_not_in_allowlist.
    ENDTRY.
  ENDMETHOD.


  METHOD convert_587.
    DATA(ld_result) = mo_cut->convert_arabic_to_roman( 587 ).

    cl_abap_unit_assert=>assert_equals( exp = `DLXXXVII`
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_611.
    DATA(ld_result) = mo_cut->convert_arabic_to_roman( 611 ).

    cl_abap_unit_assert=>assert_equals( exp = `DCXI`
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_789.
    DATA(ld_result) = mo_cut->convert_arabic_to_roman( 789 ).

    cl_abap_unit_assert=>assert_equals( exp = `DCCLXXXIX`
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_9.
    DATA(ld_result) = mo_cut->convert_arabic_to_roman( 9 ).

    cl_abap_unit_assert=>assert_equals( exp = `IX`
                                        act = ld_result ).
  ENDMETHOD.


  METHOD convert_999.
    DATA(ld_result) = mo_cut->convert_arabic_to_roman( 999 ).

    cl_abap_unit_assert=>assert_equals( exp = `CMXCIX`
                                        act = ld_result ).
  ENDMETHOD.
ENDCLASS.

 

Let's now run the test class. All test cases should run on red, as we have not yet stored any logic. As expected, we now have a lot of unit tests that are initially running on red.

 

Mapping

In the first step, we need to map the numbers to the characters and back. To do this, we first create an internal table, which we then fill. For direct access, we create secondary keys, so that we have fast single record access, and leave the table as the default so that we can later do simpler processing using a LOOP.

TYPES: BEGIN OF ts_mapping,
         roman  TYPE string,
         arabic TYPE i,
       END OF ts_mapping.
       
TYPES tt_mapping TYPE STANDARD TABLE OF ts_mapping WITH EMPTY KEY
 WITH UNIQUE SORTED KEY by_roman COMPONENTS roman
 WITH UNIQUE SORTED KEY by_arabic COMPONENTS arabic.

 

To ensure that the data is filled at the start, we implement the constructor in the class and fill it with the data that we store as a member attribute in the class.

mt_mapping = VALUE #( ( roman = `I` arabic = 1 )
                      ( roman = `V` arabic = 5 )
                      ( roman = `X` arabic = 10 )
                      ( roman = `L` arabic = 50 )
                      ( roman = `C` arabic = 100 )
                      ( roman = `D` arabic = 500 )
                      ( roman = `M` arabic = 1000 ) ).

 

You can also easily create the constructor using CTRL + 1 on the class name. Here you will find suggestions for common implementations.

 

Roman to Arabic

Let's start with the easiest use case, converting Roman numerals to Arabic. Let's start by processing the numbers. To do this, we go through the string character by character and read the current value, which we add to our result. If we cannot find the character because it does not exist, we trigger an exception.

DO strlen( id_roman ) TIMES.
  DATA(ld_actual_roman) = substring( val = id_roman
                                     off = sy-index - 1
                                     len = 1 ).

  TRY.
      DATA(ld_actual_value) = mt_mapping[ KEY by_roman COMPONENTS roman = ld_actual_roman ]-arabic.
    CATCH cx_sy_itab_line_not_found.
      RAISE EXCEPTION NEW cx_abap_not_in_allowlist( ).
  ENDTRY.

  rd_result += ld_actual_value.
ENDDO.

 

Now we can run our unit tests to check whether the logic already works. As you can see, we are already covering a special case and the direct characters also work.

 

There seems to be a problem with the subtraction rule here, as we are not taking this into account. To do this, we save the last value of the determination and check whether the last value was greater than or equal to the current value. Otherwise, we have to subtract the last value again and add the current value minus the last value. The logic for this would look like this.

IF ld_last_value >= ld_actual_value.
  rd_result += ld_actual_value.
ELSE.
  rd_result = rd_result - ld_last_value + ld_actual_value - ld_last_value.
ENDIF.

ld_last_value = ld_actual_value.

 

If we now run our unit tests again, we are almost there and only have to catch a special case when an empty string is passed.

 

To do this, we can implement a simple check at the beginning of the method and then exit the method again via an exception.

IF id_roman IS INITIAL.
  RAISE EXCEPTION NEW cx_abap_not_in_allowlist( ).
ENDIF.

 

Finally, we run the unit test again and our method works so far.

 

Arabic to Roman

Now it's time to implement the second method to convert an Arabic number to a Roman number. In this case, let's start with a special case and compare the numbers that are outside the rule range.

IF id_arabic < 1 OR id_arabic > 3999.
  RAISE EXCEPTION NEW cx_abap_not_in_allowlist( ).
ENDIF.

 

If we run the unit tests, we get the first feedback on these cases. This means that the special cases are already covered.

 

In the next step, we generate the Roman numerals, starting with the largest number. To do this, we use step -1 to go backwards through the internal table and start with the largest number. In the next step, we calculate how often the current number fits into the open value and generate part of the number. At the end of the loop we subtract the total from the outstanding amount and append the result.

DATA(ld_open) = id_arabic.

LOOP AT mt_mapping INTO DATA(ls_mapping) STEP -1.
  DATA(ld_actual_value) = 0.
  DATA(ld_part) = ``.

  WHILE ( ld_open - ld_actual_value ) >= ls_mapping-arabic.
    ld_actual_value += ls_mapping-arabic.
    ld_part &&= ls_mapping-roman.
  ENDWHILE.

  ld_open -= ld_actual_value.
  rd_result &&= ld_part.
ENDLOOP.

 

If we run the unit tests, we get more positive results, but the logic does not seem to be complete yet. On closer inspection, you will notice that we generate the same character more than three times (see rule) and also violate the special rule with more than one intermediate character.

 

To do this, we now have to expand the customizing to get more information about the characters. Which is the higher character and which is needed for the subtraction rule. Accordingly, the customizing now looks like this:

TYPES: BEGIN OF ts_mapping,
         roman  TYPE string,
         arabic TYPE i,
         low    TYPE string,
         high   TYPE string,
         single TYPE abap_boolean,
       END OF ts_mapping.
       
mt_mapping = VALUE #( ( roman = `I` arabic = 1 low = `I` high = `V` )
                      ( roman = `V` arabic = 5 low = `I` high = `X` single = abap_true )
                      ( roman = `X` arabic = 10 low = `X` high = `L` )
                      ( roman = `L` arabic = 50 low = `X` high = `C` single = abap_true )
                      ( roman = `C` arabic = 100 low = `C` high = `D` )
                      ( roman = `D` arabic = 500 low = `C` high = `M` single = abap_true )
                      ( roman = `M` arabic = 1000 low = `C` high = `M` ) ).    

 

Now we add the logic with the two special rules. To do this, we read the corresponding high and low values for the current mapping. We then compare the two rules:

  • This character may only appear once
  • Are 4 or more identical characters used

 

DATA(ls_low) = mt_mapping[ KEY by_roman COMPONENTS roman = ls_mapping-low ].
DATA(ls_high) = mt_mapping[ KEY by_roman COMPONENTS roman = ls_mapping-high ].

IF ( ls_mapping-single = abap_true AND ( ls_high-arabic - ls_low-arabic ) <= ld_open ) 
 OR strlen( ld_part ) > 3.
  ld_part = ls_low-roman && ls_high-roman.
  ld_actual_value = ls_high-arabic - ls_low-arabic.
ENDIF.

 

If we now carry out our unit test at the end, all cases are green, the logic has been fully implemented.

 

Complete example

The complete implementation of the converter now looks like this, where you can find the complete test class in the upper area.

CLASS zcl_bs_demo_roman_numbers DEFINITION
  PUBLIC FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    METHODS constructor.

    METHODS convert_roman_to_arabic
      IMPORTING id_roman         TYPE string
      RETURNING VALUE(rd_result) TYPE i
      RAISING   cx_abap_not_in_allowlist.

    METHODS convert_arabic_to_roman
      IMPORTING id_arabic        TYPE i
      RETURNING VALUE(rd_result) TYPE string
      RAISING   cx_abap_not_in_allowlist.

  PRIVATE SECTION.
    TYPES: BEGIN OF ts_mapping,
             roman  TYPE string,
             arabic TYPE i,
             low    TYPE string,
             high   TYPE string,
             single TYPE abap_boolean,
           END OF ts_mapping.
    TYPES tt_mapping TYPE STANDARD TABLE OF ts_mapping WITH EMPTY KEY
     WITH UNIQUE SORTED KEY by_roman COMPONENTS roman
     WITH UNIQUE SORTED KEY by_arabic COMPONENTS arabic.

    DATA mt_mapping TYPE tt_mapping.
ENDCLASS.


CLASS zcl_bs_demo_roman_numbers IMPLEMENTATION.
  METHOD constructor.
    mt_mapping = VALUE #( ( roman = `I` arabic = 1 low = `I` high = `V` )
                          ( roman = `V` arabic = 5 low = `I` high = `X` single = abap_true )
                          ( roman = `X` arabic = 10 low = `X` high = `L` )
                          ( roman = `L` arabic = 50 low = `X` high = `C` single = abap_true )
                          ( roman = `C` arabic = 100 low = `C` high = `D` )
                          ( roman = `D` arabic = 500 low = `C` high = `M` single = abap_true )
                          ( roman = `M` arabic = 1000 low = `C` high = `M` ) ).
  ENDMETHOD.


  METHOD convert_arabic_to_roman.
    IF id_arabic < 1 OR id_arabic > 3999.
      RAISE EXCEPTION NEW cx_abap_not_in_allowlist( ).
    ENDIF.

    DATA(ld_open) = id_arabic.

    LOOP AT mt_mapping INTO DATA(ls_mapping) STEP -1.
      DATA(ld_actual_value) = 0.
      DATA(ld_part) = ``.

      WHILE ( ld_open - ld_actual_value ) >= ls_mapping-arabic.
        ld_actual_value += ls_mapping-arabic.
        ld_part &&= ls_mapping-roman.
      ENDWHILE.

      DATA(ls_low) = mt_mapping[ KEY by_roman COMPONENTS roman = ls_mapping-low ].
      DATA(ls_high) = mt_mapping[ KEY by_roman COMPONENTS roman = ls_mapping-high ].

      IF ( ls_mapping-single = abap_true AND ( ls_high-arabic - ls_low-arabic ) <= ld_open ) OR strlen( ld_part ) > 3.
        ld_part = ls_low-roman && ls_high-roman.
        ld_actual_value = ls_high-arabic - ls_low-arabic.
      ENDIF.

      ld_open -= ld_actual_value.
      rd_result &&= ld_part.
    ENDLOOP.
  ENDMETHOD.


  METHOD convert_roman_to_arabic.
    IF id_roman IS INITIAL.
      RAISE EXCEPTION NEW cx_abap_not_in_allowlist( ).
    ENDIF.

    DATA(ld_last_value) = 0.

    DO strlen( id_roman ) TIMES.
      DATA(ld_actual_roman) = substring( val = id_roman
                                         off = sy-index - 1
                                         len = 1 ).

      TRY.
          DATA(ld_actual_value) = mt_mapping[ KEY by_roman COMPONENTS roman = ld_actual_roman ]-arabic.
        CATCH cx_sy_itab_line_not_found.
          RAISE EXCEPTION NEW cx_abap_not_in_allowlist( ).
      ENDTRY.

      IF ld_last_value >= ld_actual_value.
        rd_result += ld_actual_value.
      ELSE.
        rd_result = rd_result - ld_last_value + ld_actual_value - ld_last_value.
      ENDIF.

      ld_last_value = ld_actual_value.
    ENDDO.
  ENDMETHOD.
ENDCLASS.

 

Summary

The exercise is only a small practical insight into the topic of Test Driven Development (TDD) and not the complete theory.

 

Advantages

However, we can take a few advantages from the application straight away:

  • We thought about the test cases and even the exceptions.
  • We only created as much source code as was necessary for the application and the test.
  • During development, the unit tests were a safety net that gave us quick feedback on the current state of development.
  • Our Application is equipped with test cases immediately after completion.
  • We have achieved a high level of source code coverage.

 

 

Disadvantages

In addition to the many advantages, you should also look at the disadvantages:

  • A lot of discipline and time in the conceptual design before the actual development of the solution is carried out.

 

Conclusion

Test Driven Development requires a high degree of a certain amount of restraint on your part as a developer, so that you don't start directly with the implementation of the logic, but first make the actual body available. You think about testability and are rewarded with implemented unit tests. Do you have another solution? Then post it in the comments.


Included topics:
QuickABAP in PracticeTDDTest Driven Development
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 in Practice - String Processing

Category - ABAP

In this practical example we look at the string processing to determine the CDS names in CamelCase and how you can implement this with ABAP.

10/15/2024

ABAP in Practice - Merge data sets

Category - ABAP

How do we merge two different data sets in ABAP, especially with regard to Modern ABAP? A practical task for this topic.

09/17/2024

ABAP in Practice - Modern ABAP

Category - ABAP

In this small task we look at existing classic ABAP source code and try to optimize it according to Modern ABAP.

08/27/2024

ABAP Quick - Performance Data Filtering

Category - ABAP

Which statement do you use in ABAP to filter internal tables and is it performant? Read more in this article.

08/13/2024

ABAP in Practice - Type Conversion

Category - ABAP

How would you perform this type conversion in ABAP? A practical example and a suggested solution.

07/16/2024