SQLScript Unit Tests, das End-User Test Framework
Veröffentlicht am 30. Dezember 2019 von | News | SQLScript |
Mit der Version 2.0 SPS04 der SAP HANA Datenbank wurde das sogenannte "End-User Test Framework in SQLScript" eingeführt. Damit ist es möglich, SQLScript Unit Tests in Form von Benutzerdefinierte Bibliotheken (UDL) zu erstellen. Diese können dann mit dem Aufruf der Prozedur SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA
automatisch ausgeführt werden.
Was wird getestet?
Meistens werden Testfälle verwendet, um für ein Unterprogramm zu prüfen, ob bei einer vorgegebenen Eingabe auch die erwartete Ausgabe erzeugt wird. Im Falle von Datenbanken handelt es sich also um Prozeduren und Funktionen, die vornehmlich getestet werden. Es lässt sich aber auch der Zustand der Datenbank testen, in dem wir beispielsweise die Anzahl der Datensätze in einer Tabelle abfragen. So können wir bei dem folgenden Beispiel prüfen, ob die Skripte für das Demo Datenmodell erfolgreich waren, und die erwartete Anzahl von Datensätzen generiert haben.
Beispiel
Um das Konzept des Test Framework zu erläutern, starten wir mit einem einfachen Beispiel. Im Listing 1.2 finden Sie eine Testbibliothek, die wirklich nur das Nötigste enthält. Sie besteht nur aus einer Testprozedur T_AUFGABEN_CNT
. Diese prüft, ob in der Tabelle AUFGABEN
genau 1000 Einträge enthalten sind.
CREATE LIBRARY test_demo_dm
LANGUAGE SQLSCRIPT TEST
AS BEGIN
@test()
PUBLIC PROCEDURE t_aufgaben_cnt
AS BEGIN
USING sqlscript_test AS test;
test:expect_eq((SELECT COUNT(*) FROM aufgaben),
1000 );
END;
END;
Um diesen SQLScript Unit Test in unserer Testbibliothek auszuführen, rufen wir in der SQL-Konsole die folgende Prozedur auf. Gegebenenfalls müssen Sie den Namen des Schemas anpassen:
CALL SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA('{"schema":"SYSTEM",
"library":"TEST_DEMO_DM"}', ?, ?, ?);
Das Ergebnis dieses Prozeduraufrufes sind 3 Tabellen. In unserem Falle ist nur in der Ersten auch tatsächlich ein Eintrag vorhanden, weil der Test erfolgreich war. Sobald ein Test scheitert, wird in der 2. Tabelle eine Meldung ausgegeben und die 3. Tabelle enthält Details zum Call-Stack der Fehler. Weiter unten ist ein Beispiel für die Ausgegebenen Tabellen
Die Sprache der Tests
Als erstes fällt an dem kleinen Beispiel auf, dass die Bibliothek mit der Sprache SQLSCRIPT TEST
angelegt wird. Damit werden Testbibliotheken von produktiven Bibliotheken unterschieden. Tatsächlich handelt es sich bei der Implementierung der Test aber auch um SQLScript.
Pragmas für Prozeduren
Um die einzelnen Prozeduren der Testbibliotheken zu klassifizieren, werden Pragmas eingesetzt. Die wichtigste Rolle spielen die die parameterlosen Testprozeduren. Diese werden durch ein vorangestelltes Pragma @test()
markiert.
Um einen definierten Systemzustand vor dem Test herzustellen, kann mit dem Pragma @TestSetUpLibrary()
eine entsprechende Prozedur markiert werden.
Nach der Ausführung der Tests wird gegebenenfalls die Prozedur mit dem Pragma @TestTearDownLibrary()
aufgerufen, um nach den Testprozeduren wieder aufzuräumen.
Prüfprozeduren
Innerhalb der Testprozeduren können mit Hilfe der Prüfprozeduren der Bibliothek SQLSCRIPT_TEST
die Zustände des Programms verifiziert werden. Die unterschiedlichen Prüfprozeduren finden Sie in Tabelle 1.1. Als Parameter Wert 1 bzw. 2 kann jeder beliebiger skalarer Ausdruck verwendet werden.
Prüfprozedur | Beschreibung |
---|---|
EXPECT_EQ(<Wert1>, <Wert2>) | Prüft, ob beide Werte gleich sind |
EXPECT_NE(<Wert1>, <Wert2>) | Prüft, ob die beiden Werte unterschiedlich sind |
EXPECT_GE(<Wert1>, <Wert2>) | Prüft, ob Wert 1 grösser oder gleich dem Wert 2 ist |
EXPECT_GT(<Wert1>, <Wert2>) | Prüft, ob Wert 1 grösser als Wert 2 ist |
EXPECT_LE(<Wert1>, <Wert2>) | Prüft, ob Wert 1 kleiner oder gleich dem Wert 2 ist |
EXPECT_LT(<Wert1>, <Wert2>) | Prüft, ob Wert 1 kleiner als Wert 2 ist |
EXPECT_NULL(<Wert>) | Prüft, ob der Wert NULL ist |
EXPECT_TABLE_EQ(<Tabelle1>, <Tabelle2>[,<Reihenfolge ignorieren>]) | Prüft, ob die beiden Tabellen identisch sind. Die Reihenfolge spielt keine Rolle, solange nicht das entsprechende Flag auf FALSE gesetzt wird. |
FAIL(<Nachricht>) | Der Test wird auf gescheitert gesetzt und die Nachricht wird ausgegeben |
Modularisierung in der Testbibliothek
Diese Prüfprozeduren unserer SQLScript Unit Tests müssen nicht direkt in der Testprozedur aufgerufen werden. Es kann innerhalb der Testbibliothek auch weiter modularisiert werden. Wenn beispielsweise mehrere Tabellen auf die Anzahl der enthaltenen Datensätze überprüft werden sollten, so bietet es sich an, diesen Teil des Codes in eine separate Prozedur auszulagern, um unnötige Wiederholungen zu vermeiden.
In Listing 1.3 wurde die Logik, um die Anzahl der Datensätze innerhalb einer Tabelle zu prüfen, in eine private Prozedur ausgelagert. Damit ist es ein Leichtes, auch sehr viele Tabellen zu prüfen, ohne dass man den gleichen Code jedes Mal wiederholen muss.
CREATE LIBRARY TEST_DEMO_DM
LANGUAGE SQLSCRIPT TEST
AS BEGIN
PRIVATE PROCEDURE check_table_count
(IN iv_tabname NVARCHAR(30),
IN iv_expected_count INTEGER)
AS BEGIN
USING sqlscript_test AS test;
DECLARE lv_query NVARCHAR(5000);
DECLARE lv_count INTEGER;
lv_query = 'SELECT COUNT(*) FROM ' || :iv_tabname;
EXEC lv_query INTO lv_count;
test:expect_eq( :lv_count, :iv_expected_count );
END;
@test()
PUBLIC PROCEDURE t_table_count
AS BEGIN
check_table_count( 'AUFGABEN', 1000);
check_table_count( 'BENUTZER', 30);
check_table_count( 'STATUS', 6);
check_table_count( 'STATUS_TEXT', 12);
--check_table_count( 'STATUS_TEXT', 13);
END;
END;
Testergebnis
Wenn wir die obige Testbibliothek ausführen und alles richtig gemacht haben, dann werden wir keine Fehlermeldung erhalten. Zur Demonstration habe ich die Parameter für die Tabelle STATUS_TEXT
verändert. Das Ergebnis der drei Rückgabetabellen des Tests sehen Sie in den folgenden drei Abbildungen. Die erste Tabelle zeigt uns, dass die Testprozedur in der Testbibliothek mit dem Ergebnis FAILED
ausgeführt wurde:
In der zweiten Tabellen finden wir den Grund für den Fehler. In unserem Falle stimmt die Anzahl der Datensätze nicht.
Die dritte Tabelle liefert jetzt den zugehörigen Call Stack.
Weiterführende Konzepte
Neben diesen grundlegenden Konzepten gibt es auch noch die Möglichkeit, mit Hilfe von sogenannten Konfigurationen unterschiedliche Vorbedingungen für die Testprozeduren zu erstellen.
Die Testprozeduren wiederum können durch eine Klassifizierung in Gruppen eingeteilt werden.
Beim Aufruf der Prozedur SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA
kann man ein JSON Dokument mitgeben, dass im Detail festlegt, welche Prozeduren mit welchen Klassifikationen in welche Konfigurationen ausgeführt werden sollen.
Diese Details finden Sie in der Referenzdokumentation SAP HANA SQLScript Reference for SAP HANA Platform.
Bewertung
Mit dem Test Framework haben wir jetzt ein sehr nützliches Instrument in der Hand, mit dem wir unsere Programme auf der Ebene der Datenbank automatisiert testen können. Die Erstellung von Unit Tests ist mittlerweile weit verbreiteter Standard, der somit auch für SQLScript Entwicklungen anwendbar ist. Auch die Testgetriebene Entwicklung (TDD) ist mit dem Framework möglich.