This is a test message to test the length of the message box.
Login
ABAP Unit Altobjekte
Erstellt von Software-Heroes

ABAP Unit - Altobjekte

In diesem Artikel geht es um sogenannten Legacy Code und wie du auch dort ABAP Unit verwenden kannst. Empfehlen können wir diese Art aber nur eingeschränkt.

Werbung

Der Begriff Altobjekt klingt etwas abwertend, wenn es um Reports und Funktionsbausteine geht, doch hier geht es auch um die Möglichkeiten, die man beim Test hat. Mehr dazu in diesem Artikel.

 

Report

Du hast noch einen alten Report im System der oft von dir überarbeitet wird und du deshalb ein paar Tests implementieren willst, damit zukünftige Entwicklungen stabil implementiert werden können? Eine Testklasse in einem Report zu implementieren ist kein Problem, dabei solltest du allerdings zwei wichtige Punkte beachten:

  • Spaghetti-Code kann nicht getestet werden, da er keine aufrufbaren Unterroutinen zur Verfügung stellt
  • Forms oder Methoden sollten mit ordentlichen Schnittstellen ausgestattet sein und auf so wenig wie möglichen globalen Daten basieren

 

Wenn du also bereits saubere Unterroutinen (Methoden oder Forms) implementiert hast, ist es kein Problem eine Testklasse zu implementieren. Dazu zwei Beispiele eines Reports die inhaltlich das Gleiche machen. Es werden Daten zum Buchungskreis gelesen, in eine Tabelle aufgenommen und diese Dann per CL_DEMO_OUTPUT ausgegeben.

Das erste Beispiel mit einer Umsetzung als lokale Klasse und einer Testklasse:

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( ).

 

Das zweite Beispiel noch mit klassischen FORM Routinen und einer Testklasse:

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.

 

Funktionsbaustein

Funktionsbausteine können von dir genauso getestet werden und eignen sich fast sogar besser dazu als ein Report. Das liegt an der Kapselung der Daten und der Schnittstelle, die ein Funktionsbaustein von vornherein mit sich bringt. Wenn du in das Rahmenprogramm einer Funktionsgruppe schaust, findest du bereits viele auskommentierte Includes, die für verschiedene Dinge vorgesehen sind.

 

Das Include mit der Endung T99 kann für Tests der Funktionsbausteine der Funktionsgruppe genutzt werden. Dafür legen wir einen einfachen Baustein im System an, der für uns eine einfache Berechnung durchführen soll.

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.

 

Im Anschluss legen wir das Include an und implementieren die Testklasse, die dann den Funktionsbaustein aufruft. In diesem Fall haben wir als Beispiel einmal nur eine Testmethode angelegt.

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.

 

Damit ist es einfach möglich die Funktionsbausteine, Klassen und Forms innerhalb einer Funktionsgruppe ebenfalls mit Tests auszustatten und bei jeder Änderung mit zu testen.

 

Einschränkungen

Dabei gibt es für “Altobjekte” noch kleine Einschränkung, denn es können nicht alle Techniken angewandt werden, die wir in diesem Buch behandeln. So sind zum Beispiel keine SEAMs verfügbar.

Ein kleiner Tipp von unserer Seite für dich ist deshalb, am besten alle Entwicklungen in globalen Klassen durchführen und Funktionsbausteine, sowie Reports nur als Hüllen für den Aufruf verwenden, damit ist der Großteil der Logik sauber im OO verschalt und du kannst die volle Effizienz mit ABAP Unit ausschöpfen. Mehr dazu werden wir dir noch im Architektur Artikel dieser Serie erzählen.

 

Fazit

Auch für Altobjekte oder Legacy Code kannst du ABAP Unit Tests schreiben, dafür muss der Code allerdings einige Voraussetzungen erfüllen, damit dies auch möglich ist. Doch je mehr Unit Tests du im System hast und damit eine hohe Abdeckung, desto eher fallen Probleme bei Anpassungen auf.


Enthaltene Themen:
ABAP UnitABAPUnit TestsAltobjekte
Kommentare (0)

ABAP Unit - Tipps

Kategorie - ABAP

Zum Abschluss der Serie noch ein paar Tipps die wir dir mit auf den Weg geben wollen. Hier geht es um Shortcuts und allgemeine Hinweise zu den Tests.

12.11.2021

ABAP Unit - Software-Architektur

Kategorie - ABAP

Wie könnte die Ziel Architektur in einem SAP System aussehen, wenn wir uns die eigenen Software Komponenten anschauen? Dies wollen wir in diesem Artikel klären.

05.11.2021

ABAP Unit - Testbarer Code (Teil 3)

Kategorie - ABAP

Hier schauen wir uns die Möglichkeiten etwas genauer an, wie man abhängige Komponenten im eigenen Coding zur Testlaufzeit deaktivieren können.

29.10.2021

ABAP Unit - Testbarer Code (Teil 2)

Kategorie - ABAP

In diesem Artikel geht es um das Thema Test Isolation und wie es unseren Code testbarer macht.

22.10.2021

ABAP Unit - Testbarer Code (Teil 1)

Kategorie - ABAP

In diesem Artikel schauen wir uns an, wie du auch in älterem Code sauber neue Funktionen implementieren und du diese im Anschluss auch testen kannst.

08.10.2021