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

ABAP Unit - Altobjekte

87

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)



Und weiter ...

Bist du zufrieden mit dem Inhalt des Artikels? Wir posten jeden Freitag neuen Content im Bereich ABAP und unregelmäßig in allen anderen Bereichen. Schaue bei unseren Tools und Apps vorbei, diese stellen wir kostenlos zur Verfügung.


ABAP Unit - Testausführung

Kategorie - ABAP

Welche Möglichkeiten gibt es zur Ausführung von ABAP Unit und welche versteckten Funktionen kennst du vielleicht noch nicht? Mehr Details zu den verschiedenen Modi in diesem Artikel.

25.06.2024

ABAP Unit - Automatisierung

Kategorie - ABAP

Wann gehen in der Entwicklung Objekte kaputt und welche Seiteneffekte können Anpassungen haben? In diesem Artikel schauen wir uns das Thema einmal näher an.

05.01.2024

ABAP Unit - TDF (Function Double)

Kategorie - ABAP

Schauen wir uns in diesem Artikel einmal an, wie wir mit Funktionsbausteinen als Abhängigkeit umgehen können, ohne diese mitzutesten.

07.04.2023

RAP - ABAP Unit (Service)

Kategorie - ABAP

Wie testet man den Service einer Schnittstelle oder RAP App eigentlich automatisch? In diesem Artikel schauen wir uns Unit Tests für OData Services an.

20.01.2023

RAP - ABAP Unit (Business Objekt)

Kategorie - ABAP

An dieser Stelle schauen wir uns einmal an, wie wir unser RAP Business Objekt automatisch testen können, um so alle wichtigen Funktionen per Knopfdruck zu prüfen.

13.01.2023