top of page
Pure_Consulting_2025_009_web_edited.jpg

Unit Tests für RAP Business Objects

22. Sept.
6 Min. Lesezeit

Aktualisiert: 29. Sept.

ABAP Unit kennen die meisten EntwicklerInnen. Man instanziiert eine normale Klasse, ruft eine Methode auf und prüft das Ergebnis. Bei einem RAP Business Object funktioniert das so nicht. Der Zugriff läuft über EML, die Daten landen zuerst im Transactional Buffer und die eigentliche Logik greift oft erst in der Save Sequence. Wer ein RAP BO testen will, braucht deshalb eine Testumgebung, die diesen Lifecycle abbildet und die Datenbankzugriffe mockt.


In diesem Beitrag bauen wir eine vollständige Testklasse auf: Setup der Testumgebung,

CRUD Operationen, Validations und Actions.


Das Beispiel


Als Beispiel dient ein bewusst kleines, Draft-fähiges Business Object ZR_REVIEW mit den

Feldern text, author, status und rating. Damit die Tests nachvollziehbar bleiben, hier der

relevante Ausschnitt aus der Behavior Definition:



Drei Dinge daraus sind für die Tests relevant: die Persistenztabelle zreview und die Draft-

Tabelle zreview_d, die Validation validateAuthor, die auf save läuft sowie die beiden Actions

setStatus (instanzgebunden, mit Parameter) sowie resetAll (statisch, an die Entität

gebunden).


Lokale oder globale Testklasse


Für RAP Unit Tests gibt es zwei Ansätze:


  1. Die lokale Testklasse liegt direkt im Behavior Pool im Tab “Test Classes”. Über LOCAL

FRIENDS bekommt sie Zugriff auf die privaten Methoden der Handler Klasse. Sie ist erste

Wahl, wenn wir die Implementierung des BO absichern wollen, und sie wandert

automatisch mit dem Behavior Pool durch den Transportweg.

  1. Die globale Testklasse testet das BO von außen wie ein beliebiger Consumer. Das eignet

sich für Szenario- und Integrationstests über mehrere Objekte hinweg.


Wir nutzen hier die lokale Variante.


Die Testumgebung: zwei Environments, nicht eines


Der häufigste Fehler beim Einstieg: Es wird nur CL_CDS_TEST_ENVIRONMENT aufgesetzt. Das

reicht nicht.


CL_CDS_TEST_ENVIRONMENT deckt die Lesezugriffe ab. Wichtig für das Verständnis: Das CDS Test Double Framework doppelt nicht die CDS Entität selbst, sondern deren Abhängigkeiten.

Übergeben wird die CDS Entität, ersetzt werden die darunter liegenden Datenquellen.

Genau deshalb haben unsere Mock-Daten die Struktur der Tabelle zreview und nicht die der

View.


CL_OSQL_TEST_ENVIRONMENT erzeugt Test Doubles für die Datenbanktabellen im ABAP SQL

Zugriff. Das brauchen wir, sobald geschrieben wird. Ein Update ohne OSQL Environment

schlägt fehl, weil der Datensatz beim Lesen aus der Tabelle nicht gefunden wird. Auch die

abschließende Verifikation per SELECT in der Testmethode läuft gegen dieses Double.


In die Dependency List gehören die Persistenztabelle und, weil unser BO Draft-fähig ist,

zusätzlich die Draft-Tabelle. Fehlt die Draft-Tabelle, laufen Draft-Szenarien gegen die echte

Datenbank.



RISK LEVEL HARMLESS und DURATION SHORT sind hier kein Beiwerk. Nur mit diesen Angaben laufen die Tests in ATC Runs und in den üblichen Qualitätsgates der Transportfreigabe

automatisch mit.


Setup und Teardown


Die Aufteilung ist wichtig, damit die Tests unabhängig voneinander bleiben:


  • class_setup baut beide Environments einmalig auf. Das ist der teure Teil und gehört

    nicht in jede Testmethode.

  • setup leert die Doubles und legt vor jedem einzelnen Test frische Mock-Daten an.

  • teardown setzt mit ROLLBACK ENTITIES alle Änderungen zurück. Ohne diese Zeile sieht

  • der nächste Test die Daten des vorherigen.

  • class_teardown räumt die Environments wieder ab.



Die Mock-Daten werden bewusst in beide Environments eingefügt. Das CDS Double bedient

die Lesezugriffe des BO, das OSQL Double die Schreibpfade und unsere Prüf-Selects.


Hängen mehrere CDS Entitäten am Test, etwa eine Composition aus Kopf und Position,

nutzen wir statt create die Variante create_for_multiple_cds und übergeben alle beteiligten

Entitäten:



Über den optionalen Parameter i_select_base_dependencies lässt sich steuern, ob die Doubles

auf Ebene der Basistabellen oder der direkten Vorgänger-Views erzeugt werden. Das ist

relevant, sobald die CDS Entität über mehrere Stufen aufgebaut ist.


CRUD testen


Jede Testmethode folgt demselben Dreischritt: EML Operation ausführen, COMMIT ENTITIES

auslösen, Ergebnis prüfen.


Der COMMIT ENTITIES ist nicht optional. Erst dort läuft die Save Sequence, erst dort greifen

Validations und Determinations, und erst dort werden die Daten in die gemockten Tabellen

geschrieben. Wer nur auf das FAILED des MODIFY prüft, testet die halbe Wahrheit.


Create


Zwei Details lohnen die Aufmerksamkeit. Die %control Flags müssen für jedes Feld gesetzt

sein, das übergeben wird, sonst ignoriert das Framework den Wert stillschweigend. Und

der erzeugte Key kommt aus der MAPPED Struktur über die %cid. Bei einer Early Numbering

Implementierung ist das der einzige Weg an den Schlüssel.


Update


UPDATE FIELDS ( status ) grenzt die Operation auf ein Feld ein. Das ist präziser als ein Full

Update und deckt auf, wenn im Behavior versehentlich mehr geschrieben wird als erlaubt.


Delete


Beim Delete prüfen wir bewusst auf sy-subrc = 4 statt auf ein leeres Ergebnisfeld. Das ist die

eindeutigere Aussage: Der Satz existiert nicht mehr.


Validations testen


CRUD abzusichern ist der Anfang. Die Business-Logik steckt in Validations, Determinations

und Actions, und genau dort zahlt sich Testabdeckung aus.


Wir nehmen die Validation validateAuthor, die einen leeren Author ablehnt. Getestet wird

immer in beide Richtungen. Ein Test, der nur den Gutfall prüft, würde auch dann grün

bleiben, wenn die Validation gar nicht mehr aufgerufen wird.


Wichtig ist der Prüfzeitpunkt: Validations laufen in der Save Sequence, nicht beim MODIFY.

Die Assertions gehören deshalb auf _commit_failed und _commit_reported, nicht auf die

Rückgaben der Modify-Anweisung.


Negativtest: Author leer


Positivtest: Author gefüllt


Wer die Messages selbst prüfen will, kann statt assert_not_initial auf die Message-ID und

die Nummer im %msg der Reported-Struktur zugreifen. Das macht den Test schärfer, koppelt

ihn aber an den Nachrichtentext. In der Praxis ist die Prüfung auf Message-ID und Nummer

ein guter Kompromiss.


Actions testen


Actions werden in EML über EXECUTE aufgerufen. Wir schauen uns beide Varianten an.


Instance Action: setStatus

Eine Instance Action hängt an einem konkreten Datensatz. Der Schlüssel kommt über %tky,

die Parameter über %param.



Static Action: resetAll

Eine Static Action ist nicht an eine Instanz gebunden, sondern an die Entität. Es gibt also

keinen %tky. Stattdessen muss %cid gesetzt sein. Fehlt die Angabe, quittiert das Framework

den Aufruf mit einer BEHAVIOR_CONTRACT_VIOLATION und dem Grund MISSING_CID. Das ist eine der Fehlermeldungen, an denen man beim ersten Mal zuverlässig hängen bleibt.




Tests ausführen


Die Tests starten in ADT über Ctrl+Shift+F10. Das Ergebnis erscheint im Tab “ABAP Unit”.

Grün bedeutet, dass alle Assertions gehalten haben. Rot zeigt, welche Assertion gebrochen

ist, mit erwartetem und tatsächlichem Wert.


Für die Abdeckung lohnt sich zusätzlich der ABAP Coverage Run über Ctrl+Shift+F11. Er

zeigt, welche Zweige des Behavior Pools tatsächlich durchlaufen wurden. Erfahrungsgemäß

fallen dabei genau die Fehlerpfade auf, für die noch kein Negativtest existiert.


Typische Stolpersteine


  • Nur CL_CDS_TEST_ENVIRONMENT aufgesetzt: Lesen funktioniert, Schreiben scheitert

  • Kein ROLLBACK ENTITIES im Teardown: Tests beeinflussen sich gegenseitig und die

    Reihenfolge entscheidet über Grün oder Rot

  • Assertion auf das FAILED des MODIFY statt auf das des COMMIT: Validations und

    Determinations laufen erst in der Save Sequence

  • Fehlendes %cid bei Static Actions: BEHAVIOR_CONTRACT_VIOLATION mit MISSING_CID

  • Fehlende %control Flags: Werte werden ohne Fehlermeldung verworfen

  • Draft-Tabelle nicht in der Dependency List: Draft-Szenarien laufen gegen die echte

    Datenbank

  • Environments in setup statt class_setup erzeugt: die Laufzeit der Testsuite steigt

    spürbar


FAZIT


RAP Business Objects sind testbar, sie brauchen nur das passende Fundament. Zwei Test

Environments, ein sauberes Setup und Teardown, und danach folgt jede Testmethode

demselben Muster aus EML Operation, Commit und Assertion.


Der eigentliche Gewinn entsteht nicht bei den CRUD Tests, sondern bei Validations und

Actions. Dort steckt die Business-Logik, dort ändert sich über die Laufzeit eines Projekts am

meisten, und dort verhindert eine automatisierte Testsuite die Regressionen, die sonst erst

im Test- oder Produktivsystem auffallen. Für Clean Core Entwicklungen, die regelmäßig

gegen neue Releases laufen müssen, ist das kein optionaler Komfort, sondern

Voraussetzung.


Sie möchten Ihre RAP Entwicklungen automatisiert absichern oder eine bestehende

Codebasis testbar machen? Pure Consulting unterstützt Sie von der Teststrategie über den

Aufbau der Testumgebung bis zur Integration in Ihre Transport- und Qualitätsprozesse.


Pure Consulting macht Ihre RAP-Entwicklungen fit für automatisierte Tests, von der Teststrategie bis zur nahtlosen Integration in Ihre Qualitätsprozesse.





Häufige Fragen:


Warum reicht CL_CDS_TEST_ENVIRONMENT nicht aus?

Es mockt nur die CDS Views und damit die Lesezugriffe. Schreibende Operationen greifen auf die Datenbanktabellen zu. Dafür wird zusätzlich CL_OSQL_TEST_ENVIRONMENT benötigt.


Warum ist COMMIT ENTITIES im Test nötig?

Validations, Determinations und die Save Sequence laufen erst beim Commit. Ohne Commit bleiben die Daten im Transactional Buffer und die Business-Logik wird nie ausgeführt.


Lokale oder globale Testklasse?

Die lokale Testklasse im Behavior Pool eignet sich für die Absicherung der Implementierung, inklusive Zugriff auf private Methoden. Die globale Testklasse testet das BO von außen und passt für Szenario- und Integrationstests.


Was bedeutet MISSING_CID?

Bei Static Actions fehlt die %cid. Sie ist Pflicht, weil die Zuordnung von Ergebnis und Aufruf ohne Instanzschlüssel darüber erfolgt.


Laufen die Tests gegen echte Daten?

Nein. Beide Test Environments erzeugen Test Doubles. Die Mock-Daten werden pro Test frisch gesetzt und nach jedem Test per ROLLBACK ENTITIES verworfen.


Unsere Services:




 
 
bottom of page