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

ABAP Unit - Legacy objects

This article is about so-called legacy code and how you can use ABAP Unit there too. However, we can only recommend this type to a limited extent.

The term legacy object sounds a bit derogatory when it comes to reports and function modules, but it is also about the possibilities that you have during the test. More on this in this article.

 

Report

Do you still have an old report in the system that is often revised by you and you therefore want to implement a few tests so that future developments can be implemented in a stable manner? Implementing a test class in a report is not a problem, but you should keep two important points in mind:

  • Spaghetti code cannot be tested because it does not provide any callable subroutines
  • Forms or methods should have proper interfaces and be based on as little global data as possible

 

So if you have already implemented clean subroutines (methods or forms), it is not a problem to implement a test class. Two examples of a report that do the same in terms of content. Company code data is read, recorded in a table and then output using CL_DEMO_OUTPUT.

The first example with an implementation as a local class and a test class:

REPORT ztest_report_with_class.

*** Selection screen
PARAMETERS:
  p_bukrs TYPE t001-bukrs.

*** Report logic
CLASS lcl_prog DEFINITION FINAL.
  PUBLIC SECTION.
    METHODS:
      main,

      select_company_code
        IMPORTING
                  id_bukrs               TYPE bukrs
        RETURNING VALUE(rs_company_data) TYPE t001.
ENDCLASS.

CLASS lcl_prog IMPLEMENTATION.
  METHOD main.
    DATA:
      lt_company_data TYPE STANDARD TABLE OF t001.

    INSERT select_company_code( p_bukrs ) INTO TABLE lt_company_data.

    cl_demo_output=>display_data( lt_company_data ).
  ENDMETHOD.


  METHOD select_company_code.
    SELECT SINGLE *
      FROM t001
      WHERE bukrs = @id_bukrs
      INTO @rs_company_data.
  ENDMETHOD.
ENDCLASS.

*** Local testclass
CLASS ltc_prog DEFINITION FINAL FOR TESTING
  DURATION SHORT
  RISK LEVEL HARMLESS.

  PRIVATE SECTION.
    METHODS:
      select_existing_company_code FOR TESTING RAISING cx_static_check.
ENDCLASS.

CLASS ltc_prog IMPLEMENTATION.
  METHOD select_existing_company_code.
    DATA(lo_cut) = NEW lcl_prog( ).

    DATA(ls_found) = lo_cut->select_company_code( '4711' ).

    cl_abap_unit_assert=>assert_not_initial( ls_found ).
  ENDMETHOD.
ENDCLASS.

*** Report
START-OF-SELECTION.
  NEW lcl_prog( )->main( ).

 

The second example with classic FORM routines and a test class:

REPORT ztest_report_with_forms.

*** Selection screen
PARAMETERS:
  p_bukrs TYPE t001-bukrs.

*** Report
START-OF-SELECTION.
  PERFORM main.

*** Report logic
FORM main.
  DATA:
    lt_company_data TYPE STANDARD TABLE OF t001,
    ls_company_data TYPE t001.

  PERFORM select_company_code
    USING p_bukrs
    CHANGING ls_company_data.

  INSERT ls_company_data INTO TABLE lt_company_data.

  cl_demo_output=>display_data( lt_company_data ).
ENDFORM.

FORM select_company_code USING p_bukrs TYPE t001-bukrs
                         CHANGING cs_company_code TYPE t001.
  SELECT SINGLE *
    FROM t001
    WHERE bukrs = @p_bukrs
    INTO @cs_company_code.
ENDFORM.

*** Local testclass
CLASS ltc_prog DEFINITION FINAL FOR TESTING
  DURATION SHORT
  RISK LEVEL HARMLESS.

  PRIVATE SECTION.
    METHODS:
      select_existing_company_code FOR TESTING RAISING cx_static_check.
ENDCLASS.

CLASS ltc_prog IMPLEMENTATION.
  METHOD select_existing_company_code.
    DATA:
      ls_found TYPE t001.

    PERFORM select_company_code
      USING '4711'
      CHANGING ls_found.

    cl_abap_unit_assert=>assert_not_initial( ls_found ).
  ENDMETHOD.
ENDCLASS.

 

Function module

Function modules can be tested by you in the same way and are almost even better suited than a report. This is due to the encapsulation of the data and the interface that a function module brings with it from the start. If you look into the main include of a function group, you will already find many includes commented out that are intended for different things.

 

The include with the ending T99 can be used to test the function modules of the function group. To do this, we create a simple function module in the system that is supposed to carry out a simple calculation for us.

FUNCTION z_bs_demo_calculate_two_number
  IMPORTING
    VALUE(id_number_one) TYPE i
    VALUE(id_number_two) TYPE i
  EXPORTING
    VALUE(ed_result) TYPE i.

  ed_result = id_number_one + id_number_two.
ENDFUNCTION.

 

Then we create the include and implement the test class, which then calls the function module. In this case we have only created one test method as an example.

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

  PRIVATE SECTION.
    METHODS:
      calculate_1_and_5 FOR TESTING.
ENDCLASS.

CLASS ltc_function_modules IMPLEMENTATION.
  METHOD calculate_1_and_5.
    DATA:
      ld_result TYPE i.

    CALL FUNCTION 'Z_BS_DEMO_CALCULATE_TWO_NUMBER'
      EXPORTING
        id_number_one = 1
        id_number_two = 5
      IMPORTING
        ed_result     = ld_result.

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

 

This makes it easy to equip the function modules, classes and forms within a function group with tests and to test them with every change.

 

Restrictions

There are still small restrictions for “legacy code”, because not all of the techniques that we deal with in this book can be used. For example, no SEAMs are available.

A little tip from our side for you is therefore to carry out all developments in global classes and only use function modules and reports as covers for the call, so that the majority of the logic is neatly wrapped in the OO and you can enjoy full efficiency with ABAP Unit. We will tell you more about this in the architecture article of this series.

 

Conclusion

You can also write ABAP unit tests for old objects or legacy code, but the code must meet certain requirements for this to be possible. But the more unit tests you have in the system and thus a high level of coverage, the more likely it is that you will notice problems with adjustments.


Included topics:
ABAP UnitABAPUnit TestsLegacy objects
Comments (0)

ABAP Unit - Tips

Category - ABAP

At the end of the series, a few tips that we would like to give you along the way. This is about shortcuts and general information about the tests.

11/12/2021

ABAP Unit - Software architecture

Category - ABAP

What could the target architecture look like in a SAP system if we look at our own software components? We want to clarify this in this article.

11/05/2021

ABAP Unit - Testable Code (Part 3)

Category - ABAP

Here we take a closer look at the options for deactivating dependent components in your own coding during the test period.

10/29/2021

ABAP Unit - Testable Code (Part 2)

Category - ABAP

This article is about test isolation and how it makes our code more testable.

10/22/2021

ABAP Unit - Testable Code (Part 1)

Category - ABAP

In this article, we'll look at how you can cleanly implement new functions in older code and then test it.

10/08/2021