Unit-Testing ist in vielen Programmiersprachen und -umgebungen ein etablierter Standard zur Qualitätssicherung in der Software-Entwicklung, nicht jedoch unter PL/SQL.
Über die Gründe dafür kann ich nur spekulieren. Vielleicht liegt es daran, dass der Entwickler die Technik (Abfragen, schreibende Zugriffe) nur sehr schwer von der Geschäftslogik trennen kann.
Letztlich gibt es m.E. keinen wirklichen Grund, Unitests unter PL/SQL zu unterlassen.
Im folgenden möchte ich die Technik und Tools vorstellen und einen Working-Prototype für einen einfachen PL/SQL-Unit vorstellen.
Dazu verwende ich utplsql, welches schon seit vielen Jahren Unit-Tests unter Oracle ermöglicht. In einem ersten Schritt starte ich den Unit-Test per Shell-Script.
In einem weiteren Schritt stelle ich ein Plugin für das Build-Tool gradle vor, mit dem der Test angestossen wird.
Installation von utplsql
utplsql wird nach Dokumentation installiert und kann anschliessend von allen Usern der Datenbank-Instanz verwendet werden.
Zum Test, ob utplsql richtig funktioniert, folgen wir dem Beispiel auf der utplsql-Homepage und definieren die Funktion
create or replace FUNCTION betwnStr (
string_in IN VARCHAR2,
start_in IN INTEGER,
end_in IN INTEGER
)
RETURN VARCHAR2
IS
BEGIN
RETURN SUBSTR ( string_in,start_in,end_in - start_in + 1);
END;
Als Test-Package verwende ich ebenfalls das Beispiel von der utplsql-Seite. Das Testpackage hat den Namen ut_btwnstr und definiert einen Test:
create or replace PACKAGE ut_betwnstr
IS
PROCEDURE ut_setup;
PROCEDURE ut_teardown;
PROCEDURE ut_BETWNSTR;
END ut_betwnstr;
Der Body mit der Test-Implementierung lautet:
create or replace PACKAGE BODY ut_betwnstr
IS
PROCEDURE ut_setup IS
BEGIN
NULL;
END;
PROCEDURE ut_teardown
IS
BEGIN
NULL;
END;
PROCEDURE ut_betwnstr IS
BEGIN
utAssert.eq ('Typical valid usage',
BETWNSTR( STRING_IN => 'abcdefg',
START_IN => 3,
END_IN => 5),
'cde');
END;
END;
Somit haben wir einen Test definiert, den wir aus sqlplus aufrufen:
Begin
utplsql.test (
samepackage_in => false,
package_in => 'betwnstr',
prefix_in => 'UT_',
recompile_in => false);
End;
Wichtig ist hierbei, dass utplsql eigentlich immer als Aufrufparameter den Namen des zu testenden Objekts fordert – also nicht den Namen des Testpackages!
Es gibt sicher noch andere Möglichkeiten, diesen Aufruf zu formulieren, die Ausgabe ist immer:
SQL*Plus: Release 11.2.0.3.0 Production on Thu Mar 17 18:15:43 2016
Copyright (c) 1982, 2012, Oracle. All rights reserved.
Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
.
> SSSS U U CCC CCC EEEEEEE SSSS SSSS
> S S U U C C C C E S S S S
> S U U C C C C E S S
> S U U C C E S S
> SSSS U U C C EEEE SSSS SSSS
> S U U C C E S S
> S U U C C C C E S S
> S S U U C C C C E S S S S
> SSSS UUU CCC CCC EEEEEEE SSSS SSSS
.
SUCCESS: ".betwnstr"
.
> Individual Test Case Results:
>
SUCCESS - betwnstr.UT_BETWNSTR: EQ "Typical valid usage" Expected "cde" and got
"cde"
>
> Errors recorded in utPLSQL Error Log:
>
> NONE FOUND
PL/SQL procedure successfully completed.
Disconnected from Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
Die Testausführung hat geklappt, die Tests waren erfolgreich.
Im nächsten Artikel geht es dann um die Integration von utplsql in das Build-Tool Gradle.