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

ABAP Unit - Entkopplung

109

In einer modernen ABAP Architektur ist die Entkopplung von Objekten ein wichtiger Bestandteil, um Testbarkeit herzustellen. Dabei geht es im ersten Schritt um die Erkennung und dann den eigentliche Austausch der Abhängigkeit.

Werbung


In diesem Artikel schauen wir auf die Entkopplung von Abhängigkeiten innerhalb unserer Unit-Tests und wie wichtig es ist, solche Abhängigkeiten zu entfernen.

 

Einleitung

Unit-Tests und ABAP Unit sind ein wichtiger Bestandteil der modernen ABAP-Architektur, da all unser Coding und unsere Business-Logik auf Klassen basieren. Mehr zur modernen Architektur erfährst du im Artikel, den wir letzte Woche veröffentlicht haben. Dabei können einfache Klassen relativ schnell mit ABAP Unit getestet werden. Doch wie sieht es eigentlich mit komplexen Frameworks aus, die viele Klassen, Unterobjekte und verschiedene Abhängigkeiten nutzen? Hier kommt die Entkopplung ins Spiel.

 

Entkopplung

Schauen wir uns aber zuerst einmal den Prozess an, wie wir Unit-Tests bauen und was wir in einem Test an unserer Klasse testen wollen.

 

Unit Tests

Dabei steht im Zentrum der Unit-Test, der in den meisten Fällen im Testklassen-Include der Klasse zu finden sein wird. Dieser Unit-Test bzw. mehrere Unit-Tests, wenn wir komplexe Klassen haben und mit mehreren Testklassen arbeiten möchten, soll unsere eigentliche Klasse testen. Diese Klasse wird Class Under Test oder kurz CUT genannt. Und unser Unit-Test sollte sich vor allem darauf fokussieren, diese Klasse und ihre Methoden zu testen.

 

Dabei wird in den häufigsten Fällen vor allem der Public-Anteil einer Klasse getestet. Allerdings kann es auch vorkommen, wenn eine Klasse zum Beispiel in der Verarbeitung aktiv ist und nur eine Public-Methode hat, dass die Tests auf diese Methode relativ komplex werden können, wenn wir jede private Methode mittesten wollen. Hier können die Methoden und Attribute sehr vielseitig verzweigt sein. Daher kann es durchaus Sinn machen, auch private Methoden der Klasse zu testen. Voraussetzung dafür sind vor allem stabile Methoden, die sich in Zukunft nicht allzu oft ändern werden, da wir sonst sehr oft unsere Unit Tests anpassen müssten.

 

Abhängigkeiten

Dabei können recht schnell große Abhängigkeiten zu anderen Komponenten und Frameworks innerhalb des Systems entstehen. Lesen wir Daten aus einem Core Data Service, zum Beispiel für die Konfiguration oder die Daten, die wir benötigen, kann es zu einer Abhängigkeit kommen. Weitere Abhängigkeiten sind aber auch Funktionsbausteine, die wir aufrufen, um Funktionen außerhalb des Systems zu triggern oder Prozesse innerhalb des Systems anzustoßen. Oder eine andere Klasse, der wir die Daten übergeben und die wir mit in die Verarbeitung aufnehmen. Weiterhin gibt es verschiedene andere Objekte, die wir außerhalb unserer Klasse aufrufen können und damit eine Abhängikeit zu unserer Klasse schaffen.

 

Mocking

In so einem Fall wollen wir diese Objekte in unseren Tests mocken. Das bedeutet, dass wir kontrolliert Daten zurückbekommen oder Daten übergeben, wie wir sie für unsere Klasse benötigen, ohne die eigentlichen Objekte mitzutesten. Wie du unten siehst, sollen solche Objekte selbst eigene Unit-Tests haben, sodass wir ein Netzwerk innerhalb des Systems aus verschiedenen Unit-Tests schaffen, die die verschiedenen Komponenten testen.

 

Test Double Frameworks

Dafür gibt es innerhalb des Systems das Test Double Framework oder kurz TDF. Dieses besteht aus verschiedenen Klassen und Hilfsobjekten, mit denen wir verschiedene Techniken zur Verfügung bekommen, um Bestandteile von Abhängigkeiten zu mocken. In den letzten Jahren ist dieses Framework stetig gewachsen, sodass wir aus den verschiedensten Bereichen und Technologien Test Doubles zur Verfügung haben, die wir verwenden können. An dieser Stelle einmal zwei Besonderheiten, auf die wir hinweisen wollen, die mit diesem Framework verbunden sind:

  1. Da ist das TEST SEAM, eine der einfachsten Möglichkeiten, um Code-Bestandteile auszutauschen. Dabei solltest du aber beachten, dass dies nur für den Notfall oder schwer testbare Units der Fall sein sollte. Da wir hier oft Situationen schaffen können, in denen wir zum Beispiel keinen richtigen Test durchführen. Mocken wir mit dem Test Seam zum Beispiel einen Datenbankzugriff, würden wir zwar die zurückerhaltenen Daten austauschen können, würden aber zum Beispiel nicht testen, ob der SELECT funktioniert hat, ob die Filter sauber übergeben werden und die Felder richtig befüllt werden.
  2. Der zweite Fall, den wir uns anschauen sollten, ist der Authority Check. Er kann immer nur Berechtigungen entfernen, er kann keine neuen Berechtigungen hinzufügen. Das liegt vor allem daran, dass wir auch während eines Unit-Tests ein COMMIT WORK setzen können, um so Datensätze im System zu persistieren, oder Daten lesen können, auf die wir vielleicht gar keinen Zugriff haben. Deshalb ist es aus Sicherheitsgründen nur möglich, Berechtigungen zu entfernen. Das solltest du bei deiner Automatisierung und einem technischen User berücksichtigen.

 

 

Hinweis: Du möchtest die aktuellen ABAP Unit Features dir anschauen und mit welchem Release diese verfügbar sind? Schau dazu einfach in die ABAP Feature Matrix.

 

DAOs

In der Vergangenheit haben wir auch oft gesagt, dass du ein Data Access Object, oder kurz DAO, verwenden solltest, um Abhängigkeiten zu mocken. Dies ist immer noch der Fall, wenn du auf älteren Systemen arbeitest, wo das Test Double Framework nicht verfügbar ist und du eine Entkopplung herstellen möchtest. Auf einem modernen System solltest du lieber das Test Double Framework verwenden, um Abhängigkeiten zu entfernen, da dies auch eine Menge Code und Objekte spart, die eigentlich nicht sein müssten.

 

Beispiel

Nichts ohne ABAP-Code. Deshalb schauen wir uns noch ein kleines Beispiel an, wie wir einen Core Data Service mocken und so eine Testklasse dafür erstellen.

 

Methode

Dabei haben wir in unserer nutzenden Klasse eine Methode, die uns über den aktuellen Nutzer den vollständigen Namen aus dem System liest. Dafür gibt es einen Core Data Service, den I_BusinessUserBasic, den wir lesen wollen, um das entsprechende Feld zurückzugeben. Damit haben wir eine relativ gut testbare Methode, denn wir haben einen Eingangsparameter und einen Ausgangsparameter, die wir dann über Tests automatisieren können.

METHOD use_core_data_service.
  SELECT SINGLE FROM I_BusinessUserBasic
    FIELDS PersonFullName
    WHERE BusinessPartner = @user
    INTO @result.

  IF sy-subrc <> 0.
    CLEAR result.
  ENDIF.
ENDMETHOD.

 

Phasen

Beim Test-Framework ist es wichtig, die verschiedenen Phasen des Unit-Tests zu kennen und wann welche Methode getriggert wird. Dabei gibt es die Setup- und die Teardown-Methoden jeweils für die Klasse und die einzelnen Testmethoden. Solltest du diese im Detail nicht kennen, empfehlen wir dir, dich mit den einzelnen Phasen und Methoden zu beschäftigen, um diese effizient einsetzen zu können und besser zu verstehen.

 

Testklasse

In unserer Testklasse haben wir im Moment nur einen einzigen Unit-Test. Dafür haben wir aber auch die Vorbereitungen für das Test Double auf den Standard CDS View dabei, ebenso die Setup-Methode, um die Daten vorzubereiten, und die Teardowns, um dann das Test Double wieder aufzuräumen. Die eigentliche Testmethode erstellt dann nur noch das CUT-Objekt für den Test, ruft die Testmethode für unseren Test-User auf und wir prüfen das Ergebnis dann gegen unsere Erwartungen. Erst einmal sehr viel Aufwand bei der Implementierung des Grundgerüsts und dem Mocken der Daten. Weitere Negativtests und mit verschiedenen Daten und Zuständen können wir dann einfach implementieren.

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

  PRIVATE SECTION.
    CONSTANTS user_id       TYPE string VALUE `1`.
    CONSTANTS expected_name TYPE string VALUE `Ada Lovelace`.

    CLASS-DATA sql_environment TYPE REF TO if_osql_test_environment.

    CLASS-METHODS class_setup.
    CLASS-METHODS class_teardown.

    METHODS setup.
    METHODS teardown.

    METHODS use_core_data_service FOR TESTING RAISING cx_abap_context_info_error.
ENDCLASS.

CLASS zcl_bs_demo_deco_usage DEFINITION LOCAL FRIENDS ltc_test_core_data_service.

CLASS ltc_test_core_data_service IMPLEMENTATION.
  METHOD class_setup.
    sql_environment = cl_osql_test_environment=>create( i_dependency_list = VALUE #( ( 'I_BUSINESSUSERBASIC' ) ) ).
  ENDMETHOD.


  METHOD class_teardown.
    sql_environment->destroy( ).
  ENDMETHOD.


  METHOD setup.
    DATA business_users TYPE STANDARD TABLE OF I_BusinessUserBasic WITH EMPTY KEY.

    business_users = VALUE #( ( BusinessPartner = user_id
                                PersonFullName  = expected_name ) ).
    sql_environment->insert_test_data( business_users ).
  ENDMETHOD.


  METHOD teardown.
    sql_environment->clear_doubles(  ).
  ENDMETHOD.


  METHOD use_core_data_service.
    FINAL(cut) = NEW zcl_bs_demo_deco_usage( ).

    FINAL(result) = cut->use_core_data_service( user_id ).

    cl_abap_unit_assert=>assert_equals( exp = expected_name
                                        act = result ).
  ENDMETHOD.
ENDCLASS.

 

Hinweis: Auch wenn wir einen CDS View testen, verwenden wir das SQL-Double, da wir den Zugriff auf die Daten mocken wollen. Das CDS-Double wäre hier im ABAP-Cloud-Umfeld auch nicht möglich, da die unterliegenden Tabellen und Views nicht freigegeben sind.

 

Zeit 

Nun kommt wahrscheinlich wieder der größte Faktor, wenn es um die Erstellung von diesen Tests geht, nämlich die Zeit. Viele Entwickler würden jetzt darauf hinweisen, dass sie keine Zeit haben oder innerhalb der Projekte kein Budget eingeplant wurde, um Tests für den Code zu erstellen. Hier noch der Hinweis von unserer Seite, dass mittlerweile auch AI, und speziell Agentic AI über GitHub Copilot zum Beispiel, helfen kann, solche Tests schnell und einfach zu generieren. Zum Beispiel wurden die Tests oben durch AI generiert, wodurch wir nur die Implementierung der Methode schreiben mussten und das Setup des Frameworks, die Erkennung der Abhängigkeiten und die Anlage der Testmethode durch den Agenten durchgeführt wurden. Daher ist es in der heutigen Zeit schwer verkaufbar, keine Unit-Tests mehr zu erzeugen, auch weil sie die Grundlage sind, um einfach und sicher ein System zu erweitern.

 

Fazit

Abhängigkeiten zu kennen und über das Test Double Framework auszuschalten, ist ein wichtiger Bestandteil, um eine sauber getestete Landschaft zur Verfügung zu stellen. Ebenso ist es aber auch die Grundlage, um sicher auf den Objekten zu arbeiten und Erweiterungen vorzunehmen, wenn bereits solche Tests vorhanden sind. Grundsätzlich kann auch AI mittlerweile Unit-Tests sauber generieren, Abhängigkeiten erkennen oder zumindest die Vorbereitung für die Unit-Tests für dich machen.


Enthaltene Themen:
ABAP UnitABAPUnit TestsEntkopplung
Kommentare (2)



Und weiter ...

Bist du zufrieden mit dem Inhalt des Artikels? Wir posten jeden Dienstag und 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.


031: Recycling-Heroes - Unit Testing (Configuration API)

Kategorie - YouTube

Nachdem wir die Configuration API fertiggestellt haben, schauen wir uns einmal das Thema Unit Tests an und wie wir unsere API automatisch testen können. Damit sparen wir uns später den Aufwand für manuelle Tests.

05.01.2026

ABAP Unit - TDF (Berechtigungen)

Kategorie - ABAP

Kannst du eine Berechtigungsprüfung eigentlich Mocken? In diesem Artikel schauen wir uns den Test Double für Berechtigungsprüfungen an.

11.07.2025

BTP - ABAP Unit Runner

Kategorie - ABAP

Wie kannst du deine ABAP Unit Tests auf dem ABAP Environment regelmäßig ausführen und dir die Ergebnisse zukommen lassen? Aktuell gibt es dafür keinen Standard.

11.02.2025

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