ABAP SQL Test Double Framework: Förderer von Clean Code in SAP-Anwendungen
Seite 2: In den Kontext gesetzt
Welche Rolle spielt nun das ABAP SQL Test Double Framework in diesem Zusammenhang? Ein Ziel der Nutzung von Unit-Tests ist das isolierte Testen öffentlicher Methoden. Allerdings bedeutet ein isolierter Test nicht automatisch eine Isolierung in Hinblick auf die Systemumgebung. Eine Methode kann während ihrer Ausführung auf andere Entwicklungsobjekte wie eine Datenbanktabelle oder einen ABAP Core Data Services zugreifen.
Typische Anweisungen aus dem ABAP-SQL-Bereich sind in hier SELECT, INSERT, UPDATE, MODIFY und DELETE. Sie finden sich vielfach in ABAP-Entwicklungen, und hier insbesondere die SELECT-Anweisungen in Reportings, deren Natur es ist, Daten von der Datenbank zu lesen, aufzubereiten und Anwendern darzustellen. Es bestehen also Abhängigkeiten zu anderen Entwicklungsobjekten. Damit nun ein Unit-Test erfolgreich ist, müssen diese Objekte möglicherweise ebenfalls einen genau definierten Zustand aufweisen.
Folgendes Beispiel soll das verdeutlichen: Das Business-Objekt "Bestellung" wird eindeutig über seine Bestellnummer identifiziert. Die Daten einer Bestellung sind dabei vielfältig: Kopf- und Positionsdaten, Einteilungen, Bestellentwicklungen und vieles andere mehr, verteilt über unterschiedliche Datenbanktabellen wie EKKO, EKPO, EKET und EKBE. Soll nun ein Unit-Test beispielsweise eine Methode prüfen, die zu einer per IMPORTING-Parameter festgelegten Bestellnummer die Kopfdaten mittels SELECT aus der Datenbanktabelle EKKO zur Verfügung stellt, kommt eine Abhängigkeit zum Tragen. Denn es muss ein passender Datensatz in dieser Datenbanktabelle vorhanden sein. Ansonsten schlägt der Unit-Test fehl. Das liegt nicht an der Programmierung der zu testenden Anwendungslogik, sondern an fehlenden Testdaten. Und fehlende Testdaten in einem Entwicklungssystem dürften eher die Regel als die Ausnahme sein.
Blick zurĂĽck
Historisch betrachtet ergibt die empfohlene Systemaufteilung aus Entwicklungs-, Qualitätssicherungs- und Produktivsystem auch heute noch mehr als Sinn. Die Daten des Produktivsystems werden von Zeit zu Zeit, zumindest partiell, auf das Qualitätssicherungssystem gespiegelt. So verfügt es über typische Stamm- und Bewegungsdaten aus dem Tagesbetrieb. Entwickler wiederum programmieren im Entwicklungssystem neue Anwendungslogik und transportieren diese in das Qualitätssicherungssystem. Dort führen sie ihre Entwicklertests durch und übergeben anschließend an die Fachabteilung zwecks weiterführender Tests und Abnahme – alles im Qualitätssicherungssystem.
Bei erfolgreicher Abnahme wird die neue Anwendungslogik in das Produktivsystem überführt. Ansonsten müssen Entwickler die Anwendungslogik überarbeiten, und die Prozedur wiederholt sich. Insgesamt reduziert das Vorgehen das Risiko, produktive Prozesse durch ungetestete Änderungen negativ zu beeinträchtigen.
Unit-Tests werden jedoch nicht im Qualitätssicherungssystem ausgeführt. Das würde dem erwähnten Prinzip des "frühzeitigen und häufigen Testens" widersprechen. Deswegen geschieht ihre Ausführung im Entwicklungssystem. Dort, wo der Entwickler zwar vorwiegend arbeitet, Testdaten jedoch Mangelware sind. Darüber hinaus könnte sich auch, selbst wenn bestimmte Testdaten vorhanden sind, ein weiteres Problem ergeben: die gemeinsame Nutzung von Testdaten. Entwickler könnten die Kopfdaten der Bestellung aus dem Beispiel für ihren Test verändern, während andere Entwickler diese Kopfdaten in einer speziellen Form benötigen. Beispielsweise könnte eine bestimmte Einkäufergruppe gefordert sein, anhand der ein besonderer Prozess identifiziert wird.
Abhilfe durch das ABAP SQL Test Double Framework
Genau hier hilft das ABAP SQL Test Double Framework. Es erlaubt das Erstellen eines Test Double. Das wiederum simuliert typische Quellen persistenter Daten.
Dazu gehören Datenbanktabellen, Views, ABAP Core Data Services und einige andere mehr. Die zeitliche Gültigkeit des Test Double ist dabei auf die Ausführung der Unit-Tests beschränkt. Währenddessen werden alle SQL-Anweisungen an das passende Test Double und nicht an das "reale" Entwicklungsobjekt aus dem Data Dictionary umgeleitet, zu dem eine Abhängigkeit besteht. Es findet also eine Entkopplung der Abhängigkeiten statt.
Das Erstellen eines Test Double ist einfach. Jede Testklasse mit Unit-Tests kann eine statische Methode namens CLASS_SETUP enthalten. Diese Methode wird automatisch und auch nur einmal vor Ausführung aller Unit-Tests, die in einer Testklasse enthalten sind, aufgerufen. Sinn und Zweck der Methode ist das Erledigen einmaliger Aufgaben, die zum Ausführen von Unit-Tests gegebenenfalls notwendig sind. Daher wird an der Stelle das ABAP SQL Test Double mit der statischen Methode CREATE der Klasse CL_OSQL_TEST_ENVIRONMENT auf ein statisches Klassenattribut, in dem Fall eine Referenzvariable vom Datentyp IF_OSQL_TEST_ENVIRONMENT, gebunden. Als IMPORTING-Parameter der statischen Methode CREATE übergeben Entwickler eine Liste der Objekte, zu denen sie ein Test Double benötigen. Das können zum Beispiel die Namen der Datenbanktabellen aus dem oben angeführten Beispiel sein: EKKO, EKPO, EKET und EKBE. Damit sind die Test Doubles angelegt, wenngleich sie noch keine Datensätze enthalten.
Für das Bereitstellen von Testdaten bieten sich zwei Möglichkeiten an. Sie lassen sich in der Methode CLASS_SETUP übergeben. Das ist vorteilhaft, wenn die Testdaten für alle Unit-Tests gleich sind und von diesen nicht verändert werden. Soll jeder Unit-Test seine eigenen Testdaten benötigen, kann er diese auch selbst bereitstellen. Das erfolgt allgemein durch das Definieren einer internen Tabelle vom Typ des jeweiligen Entwicklungsobjekts. Das kann etwa mit TYPE TABLE OF ... WITH KEY ..., dem Befüllen mit Testdatensätzen und der Übergabe dieser internen Tabelle an die Methode INSERT_TEST_DATA des Klassenattributs zum Verwalten der Test Doubles (Referenzvariable vom Datentyp IF_OSQL_TEST_ENVIRONMENT geschehen (siehe Methode CLASS_SETUP). Damit ist diese Aufgabe abgeschlossen und die Test Doubles sind einsatzbereit.
Das Generieren von Testdatensätzen lässt sich übrigens mit der SQL Console der ABAP Developments Tools vereinfachen. Die passende Funktion lautet "Copy all rows as ABAP value statement". Dabei werden die in der Anzeige befindlichen Datensätze als VALUE-Anweisung in die Zwischenablage kopiert. Von dort kann man sie in die Testklasse an passender Stelle übernehmen. Das erspart viel Schreib- beziehungsweise Tipparbeit. Denn manche Datenbanktabellen umfassen pro Datensatz viele hundert Felder. Solche Datensätze manuell nachzubilden kann zur Tortur werden.