
ABAP Cloud - Systemfelder (Lösung)
Wie könnte eine Lösung für ABAP Cloud aussehen, um an die Systeminformationen und -felder zu gelangen und dabei testbar und offen zu bleiben? Hier mehr.
Inhaltsverzeichnis
In diesem Artikel schauen wir uns eine mögliche Lösung für die Verwendung von Systeminformationen an und wie wir sie gestaltet haben.
Einleitung
Im letzten Artikel hatten wir uns die Systemfelder angeschaut und aus welchen Quellen wir bestimmte Informationen erhalten können. Dabei gibt es die SY bzw. SYST-Struktur, die Context Klasse und die XCO Bibliotheken, die ähnliche Ansätze zur Verfügung stellen. Aktuell werden in vielen Entwicklungen einfach die Systemfelder verwendet, diese werden aber teilweise mit ABAP Cloud obsolet. Die neuen Klassen stellen ebenfalls verschiedene Informationen zur Verfügung, sind aber nicht immer vollständig. Ebenso ist die Implementierung nicht unbedingt einfach und die Testbarkeit wird meist durch das Design eingeschränkt.
Design
In diesem Kapitel gehen wir noch einmal auf das gewählte Design und die damit verbundenen Kriterien ein.
Kriterien
Wir haben uns deshalb einmal die aktuelle Umsetzung angeschaut und einige Kriterien definiert, die wir mit der Lösung erreichen wollen:
- Zentraler Zugriffspunkt für Systeminformationen
- Beschreibende Objekte und Methoden
- Testbarkeit der Daten (Mocking)
- Dokumentation mit Hinweisen
- Einfacher Zugriff (Wenig Konfiguration, einfache Methoden)
Factory Pattern
Im Design verwenden wir eine Factory, um eine Instanz für den Zugriff zu erzeugen. In diesem Fall ist die Factory über ZCL_SYST zu erreichen und wir haben auf das Wort Factory verzichtet, um den Namen so klein wie möglich zu halten. Die verschiedenen Methoden werden im Interface ZIF_SYST definiert und die verschiedenen Typen zur Verfügung gestellt.
Aktuell stellen wir eine Standard Implementierung "DEFAULT" zur Verfügung, grundsätzlich könnten noch weitere Implementierungen gemacht werden.
Injector
Über den Injector kannst du Test-Doubles zur Verfügung stellen, ohne den eigentlichen Code anpassen zu müssen. Damit erreichen wir ein testbares Design der Komponente. Im Artikel oben wurde as Thema Injector nur angerissen, aber nicht im Detail erklärt. Der Injector hat die Möglichkeit durch eine Global Friend Beziehung direkt in der Factory ein privates Attribut zu setzen, dieses wird bei der Erzeugung der Instanz berücksichtigt, womit im Testfall unser Double verwendet wird. Der Injector selbst ist mit FOR TESTING gekennzeichnet, wodurch er nur im ABAP Unit Szenario verwendet werden kann und nicht ausversehen in produktivem Code läuft.
Verwendung
In diesem Kapitel schauen wir uns die Verwendung der Klasse an, sowie die Verbindung zum ABAP Unit Test.
Beispiel
Für unser Beispiel implementieren wir zwei Methoden, die für uns verschiedene Validierungen vornehmen sollen. Die erste Methode führt eine Berechtigungprüfung durch und mappt den SY-SUBRC auf einen booleschen Wert.
METHOD has_authority.
AUTHORITY-CHECK OBJECT 'S_APPL_LOG'
ID 'ACTVT' FIELD '02'.
RETURN xsdbool( zcl_syst=>create( )->return_code( ) = 0 ).
ENDMETHOD.
Die zweite Methode prüft auf eine User-ID und wenn es sich um einen spezifischen User handelt, dann wird ABAP_TRUE zurückgeliefert.
METHOD is_technical_user.
IF zcl_syst=>create( )->user_id( ) = 'TECHUSER'.
RETURN abap_true.
ELSE.
RETURN abap_false.
ENDIF.
ENDMETHOD.
In beiden Fällen lassen wir uns über die Methode CREATE der Klasse ZCL_SYST eine Instanz der Implementierung zurückgeben. Über dieses Objekt können wir dann auf das entsprechende Feld/Information zugreifen und uns den Inhalt zurückgeben lassen.
ABAP Unit (TDF)
Im ersten Unit Test verwenden wir das Test-Double-Framework (TDF) der SAP und erzeugen uns einen Double, um die Methode HAS_AUTHORITY damit zu testen.
DATA(double) = CAST zif_syst( cl_abap_testdouble=>create( 'ZIF_SYST' ) ).
cl_abap_testdouble=>configure_call( double )->ignore_all_parameters( )->returning( 0 ).
double->return_code( ).
Diesen Double können wir dann über den Injector einfügen und im Anschluss unseren Test durchführen. Zur Laufzeit wird dann der Double zurückgegeben.
zcl_syst_injector=>inject_syst( double ).
ABAP Unit (Double)
Die Methode IS_TECHNICAL_USER testen wir im zweiten Schritt mit einer lokalen Testklasse als Implementierung. Dabei verwenden wir PARTIALLY IMPLEMENTED, um nicht das vollständige Interface implementieren zu müssen, sondern nur unsere Methode für den Test.
CLASS ltd_system DEFINITION FOR TESTING.
PUBLIC SECTION.
INTERFACES zif_syst PARTIALLY IMPLEMENTED.
ENDCLASS.
CLASS ltd_system IMPLEMENTATION.
METHOD zif_syst~user_id.
RETURN 'TECHUSER'.
ENDMETHOD.
ENDCLASS.
Der Code der Testmethode fällt dann viel kürzer aus und wir müssen nur noch den Double erzeugen und über den Injector in die Verarbeitung geben. Im Anschluss können wir wieder die Methode wie gewohnt aufrufen und testen.
zcl_syst_injector=>inject_syst( NEW ltd_system( ) ).
ABAP Cloud
Möchtest du zum Abschluss die Komponenten in deiner Entwicklung verwenden und du setzt auf verschiedene Software Komponenten (SWC), dann musst du Bestandteile der Implementierung mit einem C1 Contract versehen. Erst dann können die Artefakte SWC übergreifend im System verwendet werden. Die folgenden Objekte müssen freigegeben werden:
- Factory ZCL_SYST
- Interface ZIF_SYST
- Injector ZCL_SYST_INJECTOR
Die eigentliche Implementierung muss nicht freigegeben werden, da sie nicht direkt genutzt wird.
Funktionen
Hier findest du ein Mapping der verschiedenen Methoden auf die Systemfelder und Funktionen, die wir mit der Klasse abbilden. Eine der Funktionen wurden als zusätzliche Hilfsfunktionen implementiert. Die Methoden enthalten in den meisten Fällen aber Implementierungen aus dem XCO Bereich, die auch für ABAP Cloud freigegeben sind.
Methode | Funktion |
---|---|
user_id | sy-uname |
user_alias | cl_abap_context_info=>get_user_alias |
system_date | sy-datum |
system_time | sy-uzeit |
timestamp | GET TIME STAMP |
timestamp_long | GET TIME STAMP |
utclong | utclong_current( ) |
user_date | sy-datlo |
user_time | sy-timlo |
time_zone | sy-zonlo |
language | sy-langu |
language_iso | - |
system_information | sy-mandt, sy-sysid, sy-cprog, sy-saprl |
index | sy-index |
table_index | sy-tabix |
database_count | sy-dbcnt |
return_code | sy-subrc |
letter_upper | sy-abcde |
letter_lower | - |
weekday | sy-fdayw |
message | sy-msgid, sy-msgno, sy-msgty, sy-msgv1, ... |
message_bapiret2 | sy-msgid, sy-msgno, sy-msgty, sy-msgv1, ... |
message_bali | sy-msgid, sy-msgno, sy-msgty, sy-msgv1, ... |
Hinweis: Aktuell gibt es nicht für alle Felder einen Ersatz, daher sind aktuell immer noch die Felder CPROG, SAPRL und FDAYW enthalten, die direkt aus den Systemfeldern kommen und damit eine Warnung in der Klasse erzeugen.
Repository
Das Mini-Framework und einige Beispiele findest du im entsprechenden GitHub Repository. Dort findest du alle Objekte und einige weitere Erklärungen zu dem Aufbau der Objekte. Das oben gezeigte Beispiel für die Implementierung und Verwendung, findest du in der Klasse ZCL_SYST_EXAMPLE.
Fazit
Systemfelder endlich verwenden und in deinen ABAP Unit Tests die Inhalte ohne weitere Anpassungen mocken? Mit unseren Hilfsklassen sollte das nun ohne weitere Probleme möglich sein.