ABAP Unit - Aufbau Testfälle
In diesem Artikel schauen wir uns einmal zusammen an, wie ein Testfall in ABAP Unit aufgebaut sein sollte, um einfach lesbar und gut strukturiert zu sein.
Inhaltsverzeichnis
In diesem Artikel wollen wir etwas genauer auf den Aufbau und das Design der Testfälle eingehen. Diese folgen ebenfalls einigen Standards und helfen anderen Entwicklern deine Testfälle schnell und einfach zu verstehen.
Testmethode
Testmethoden sollten immer dem Schema “Given - When - Then” folgen, damit sofort ersichtlich ist, was getestet wird und gegen was das Ergebnis validiert wird. Dazu noch einmal die Testmethode aus dem letzten Kapitel:
Dabei lassen sich die einzelnen Abschnitte wie folgt beschreiben:
- Given - Vorbereitung der Testinstanz und Daten die für den Testfall benötigt werden
- When - Durchführung des Tests bzw. Aufruf der Testmethode
- Then - Vergleich des Ergebnisses gegen den erwarteten Wert (Verwendung von Klasse CL_ABAP_UNIT_ASSERT)
Vorbereitung
Für die Vorbereitung der Daten und Testinstanz kannst du ebenso Hilfsmethoden in der Testklasse oder einer weiteren Hilfsklasse nutzen. Hier spielt vor allem Clean Code eine wichtige Rolle, sodass nichts redundant an Testcode ist. Alles was sich bei der Vorbereitung auslagern lässt, sollte durch andere Methoden erfüllt werden, sodass deine Testmethode den reinen Testfall abdeckt und übersichtlich bleibt.
Die Definition der Testmethode gibt mindestens die zu testende Klasse als fertige Instanz zurück.
METHODS:
prepare_cut
IMPORTING
id_companycode TYPE t001-bukrs DEFAULT ''
RETURNING VALUE(ro_cut) TYPE REF TO zcl_test_prepare.
In der Methode kann dann entsprechend, die initiale Konfiguration durchgeführt werden, um so alle Werte für die Testfälle zu initialisieren.
METHOD prepare_cut.
DATA(ld_companycode) = id_companycode.
IF ld_companycode IS INITIAL.
ld_companycode = '4711'.
ENDIF.
DATA(ls_config) = VALUE zcl_test_prepare=>ts_config(
test = abap_true
send_mail = abap_false
).
ro_cut = NEW #( ls_config ).
ro_cut->set_company_code( ld_companycode ).
ENDMETHOD.
Durchführung
Bei der Durchführung wird die zu testende Methode aufgerufen und die Schnittstelle mit entsprechenden Werten versorgt. Das Ergebnis wird am besten in einer Variablen mit dem Namen “Result” gesichert. Damit ist auch an dieser Stelle für andere Entwickler klar, dass es sich hierbei um das Ergebnis des Tests handelt.
Vergleich
In den meisten Fällen reicht es, gegen die Methode ASSERT_EQUALS zu vergleichen, doch nicht immer macht es Sinn dies zu tun oder das Ergebnis gibt es einfach nicht her. Hier solltest du ab und zu prüfen, ob nicht auch eine andere Methode in Frage kommt oder du eine ungefähre Annäherung erreichen möchtest.
Dazu ein paar Beispiele:
- Status eines Tabellenzugriffs oder einer Tabellenaktion - ASSERT_SUBRC
- Befüllung der Daten - ASSERT_NOT_INITIAL
- Instanz wurde erzeugt - ASSERT_BOUND
Code under Test
Wie du wahrscheinlich schon in einigen unserer Testmethoden gesehen hast, heißt die Instanz der Klasse, die wir testen immer “lo_cut”. Das hat auch einen einfachen Grund, denn es gibt eine weitere Sache, die man beachten sollte und das ist, dass der Code under Test (kurz CuT) auch so im Testfall benannt wird, um anderen Entwicklern klar zu machen was genau getestet wird.
Falls mehr als eine Klasse im Testfall instanziiert wird, ist die der eindeutige Hinweis auf den Testfall und welches Objekt dann getestet wird. Ebenso kann die Instanz auch als Attribut in der Testklasse definiert werden, dann bekommt sie aber ebenfalls diesen Namen.
Eine entsprechende Testmethode zu den oben genannten Code-Snippets könnte dann wie folgt aussehen. Die zu testende Klasse kannst du einfach identifizieren:
METHOD company_data_not_found.
DATA(lo_cut) = prepare_cut( ).
DATA(ls_found) = lo_cut->get_company_data( ).
cl_abap_unit_assert=>assert_initial( ls_found ).
ENDMETHOD.
Umfang
Wie viele Testfälle brauchst du nun eigentlich für dein Coding? Hierfür gibt es keine genaue Regel, sondern hier musst du dir Gedanken machen. Im ersten Schritt solltest du auf jeden Fall deine fachlichen Anforderungen an dem Code überprüfen, also was das Testobjekt eigentlich machen soll:
- Positiver Test - Du rufst das Testobjekt mit gültigen Werten auf und prüfst, ob das erwartete Ergebnis eingetreten ist und sich das Objekt richtig verhalten hat.
- Negativer Test - Du übergibst falsche Parameter und testet so das Exception Handling und das Verhalten.
- Zufall – Übergebe irgendwelche zufälligen Eingaben, um das Verhalten deines Codes auf Stabilität zu prüfen.
- Overflow Test - Du übergibst zu große Felder oder ungewöhnliche Daten, um so die internen Datentypen und Größen an die Grenzen zu bringen. Dies ist ein starker Belastungstest für das Testobjekt.
Je weiter nach unten du in der Liste kommst, desto seltener werden diese Typen von Testmethoden benötigt. Wie sehr du eine Methode stressen möchtest, liegt am Ende auch an der Zeit, die du deine Methoden testen möchtest.
Hinweis: Sollte es im Laufe des Software-Lebenszyklus zu Fehlern in bestimmten Methoden kommen, dann kannst du für diese Fehler Testfälle anlegen, sodass diese in Zukunft nicht mehr auftauchen. Dies hilft dir den manuellen Testumfang so klein wie möglich zu halten.
Fazit
Dir sollte nun etwas klarer sein wie ein Testfall strukturiert wird, um so den optimalen Nutzen zu erzielen und so kurz wie möglich zu sein. Weiterhin kannst du den Scope deiner Tests nun selbst bestimmen, um so die optimalen Testfälle zu bestimmen.