Essay – Abhandlung: Steven Feuersteins Best PL/SQL Practices und TOAD Code Tester

Steven Feuersteins Webseite: www.oracleplsqlprogramming.com
Steven Feuersteins Ressourcen zum FREE download: www.oracleplsqlprogramming.com/resources.html

Stevens Tipps:

Soviel Standard-Code verwenden wie möglich. Quest bietet gratis eine PL/SQL Library: Quest CodeGen Utility:
– Error Handling
– Logging
– TAPI (Auch auf View möglich)
usw.

Unbedingt Code in Layers aufsplitten (Siehe Folien).
Beispielsweise SQL in eigene Schicht.
Beispielsweise auch eine Utility Schicht (applikationsunabhängig) einbauen.
Schichten mit Namenskonventionen erkenntlich machen. Beispielsweise tb_…. Objekte sind ToolBox Objekte und gehören zum Utility Layer.

Code Templates erstellen. Also für Package Body und Spec mit Standard-Operationen wie init() und cleanup().

Write tiny chunks of code!
Idealerweise soll jede Function/Procedure in der Executable Section nur 20-30 Zeilen (max. 50) ausführbaren Code enthalten ! Sonst sofort in In-Line Procedures oder private Procedures im Package Body auslagern.

Code im Top-Down Ansatz schreiben: Also von der Aufgabenbeschreibung her beginnen und das Package mit “leeren” Procedures/Functions erstellen.
Also im Stil von “Pseudocode” das PL/SQL Programm bereits schreiben und leer kompilieren.
Beispiel:
begin
if summer_aller_gehälter() > gehalt_vom_chef_im_jahr(‘2002’)
then
berechne_neue_gehälter();
end if;
end;

Die 3 oben aufgeführten Methoden werden alle mit begin return null; end; (oder so ähnlich) codiert.
Am Schluss hat man so eine schöne “To-Do-Liste” welche dann einzeln auscodiert werden kann.
… most bugs will disapear 😉 …

Test-Driven-Developement mit dem Quest Code Tester (Freeware Version reicht).
Wie im Beispiel oben kann jetzt auch zu jeder dieser Methoden ein Testfall mit allen erdenklichen Test-Cases erstellt werden.
Details siehe Abschnitt “Quest Code Tester”

Quest Code Tester

Quest Code Tester FREEWARE Version: www.toadworld.com.
Quest Code Tester COMMERCIAL Version: www.quest.com/code-tester-for-oracle

Der Quest Code Tester wurde während 2 Jahren durch Steven Feuerstein für Quest entwickelt. Das Tool ist absolut neu.
Eine veraltete alternative ist utPLSQL. Wurde von Steven vor 7 Jahren entwickelt. Er selbst benützt das Tool jedoch nicht. Er verwendet auch den Quest Code Tester.

Testfälle werden NICHT codiert sondern beschrieben (deklaratives Testen).

Der Clou der Sache:
– Der Test kann jederzeit wiederholt werden.
– Auch wenn ein Jahr später am Programm etwas geändert wird kann der “alte” Test wieder gefahren werden
– Hauptmerkmal ist aber dass der Testfall erkennt ob OK oder NICHT OK !
Meine (so wie bis anhin benützten) Testscripts testen zwar auch das Verhalten, erkennen aber nicht ob das Resultat in Ordnung ist oder nicht (… wie soll es denn auch …)

Testfälle müssen VOR der Programmierung erstellt werden!
Die Testfall-Liste für jedes Programm wird für die Programmierung als To-Do-Liste verwendet.
Vorgehen: Spezifikation – Programmheader (Also die leeren Programmunits erstellen) – Testfälle beschreiben – Programm fertigcodieren.

Testfälle mit DML sind auch möglich (Eigenes Programm sollte einfach nicht commit ausführen)

API vorhanden für automatisiertes ausführen.

==> Für uns würde die Freeware Version reichen. Die Einschränkung besteht darin dass nur eine Ausgabe pro Testfall möglich ist. Ich kann also nicht gleichzeitig den Returnwert prüfen und kontrollieren ob auch noch eine Exception raised wurde.

TOAD 9.0 Tipps

In Toad 9.0 hat es einige Werkzeuge die man kaum kennt und doch sehr nützlich sind.

Der Projektmanager ist sehr hilfreich. Ist eine Art von Favoritenverwaltung für:
– Connections
– DB Objekte
– Script Files lokal
– SSH Verbindungen
– Ganze Ordner
– usw.
Dateien können direkt mit Versionierungstool Ein- und Ausgechecked werden.

Man sollte viel mehr mit “auto replace” machen.
Z.B. “sel” und Blank ergibt automatisch “select * from”

CodeExpert. Ein riesen Werkzeug mit 2 Funktionen:
a) Best Practice Advice ==> gibt für das PL/SQL Programm hinweise wo Verbesserungen möglich wären.
b) Performance Analyse! Also so was wie Embarcadero:
Scan SQL Statement mit dem “Stimmgabel Icon” = Tune SQL
Schritt 1: Sucht für das SQL Statement hunderte von möglichen Variante anhand der EXECUTION PLANS durch.
Schritt 2: Die besten Varianten anhand eines besseren Execution Plans aus Schritt 1 werden nun real ausgeführt (Last auf DB)
Schritt 3: Das Tool zeigt optisch die besten SQL Statements anhand versch. Kriterien.
(Um parsing und caching Verfälschungen zu vermindern wird jede Query mehrfach ausgeführt)

Für den DBA relevant: Zum erstellen von Testdaten kann der Data-Subset-Wizard verwendet werden.
Dieser erstellt beispielsweise 3% der Daten ausgehend von einer Basistabelle. Dies mit allen Abhängigen Datensätzen aus anderen Tabellen (natürlich via FK)

Persönliche Abschlussbemerkung

Ich bin jetzt ein (theoretisch) überzeugter Test-Driven-Developer. Ich werde mir die Freeware Version des Quest Code Testers installieren.
Ich denke mir dass die Qualität von PL/SQL Programmen mit diesem Werkzeug erheblich steigen kann.

Anmerkung 19.06.2007: API’s

Einzelne Unit-Tests können auch in einer Test-Suite zusammengruppiert werden.
Eine solche Test-Suite kann dann beispielsweise via pl/sql API gesamthaft getestet werden.
Hier der sehr einfache pl/sql code zum Testen einer Suite:

declare
vRes varchar2(600);
begin
qu_test.run_suite_by_name ('TEST-SUITE-NAME',vRes);
dbms_output.put_line('resultat: ' || vRes);
end;

Als Ergebnis erscheint aber nur SUCCESS oder FAILED. Dies für die ganze Suite!
Dies ist ok wenn SUCCESS. Problematisch bei FAILED – es ist hier nicht ersichtlich welcher Unit-Test fehlgeschlagen hat.

Solch ein einzelner Unit-Test kann dann natürlich auch sehr einfach via pl/sql API gestartet werden:

DECLARE
l_result qu_config.maxvarchar2;
l_result_row qu_result_xp.last_run_results_api_cur%ROWTYPE;
my_results qu_result_xp.last_run_results_api_rc;
BEGIN
qu_test.run_test_for2 (owner_in => USER
, NAME_IN => 'UNIT-TEST-NAME'
, result_out => l_result
, results_out => my_results
, unit_test_guid_list_in => NULL
, test_case_guid_list_in => NULL
, delimiter_in => NULL
);
DBMS_OUTPUT.put_line ('Overall result of test: ' || l_result);

LOOP
FETCH my_results
INTO l_result_row;

EXIT WHEN my_results%NOTFOUND;
DBMS_OUTPUT.put_line ( RPAD (' ', l_result_row.h_level * 2)
|| ' '
|| l_result_row.NAME
|| '-Status: '
|| l_result_row.result_status
|| '-Description: '
|| l_result_row.description
);
END LOOP;
END;

Das Resultat für einen Unit-Test sieht dann völlig anders aus. Die kompletten Testresultate wie im GUI Tool werden angezeigt:

Overall result of test: SUCCESS
SCHEMA.UNIT-TEST-NAME-Status: SUCCESS-Description: Test succeeded up to this level.
GETRESULTAT-Status: SUCCESS-Description: Test succeeded up to this level.
normal usage testfall-Status: SUCCESS-Description: Test succeeded up to this level.
Scalar is equal to the expected value?-Status: SUCCESS-Description: From Program Value of 4 = Expected Value 4
division durch 0-Status: SUCCESS-Description: Test succeeded up to this level.
Specified exception was raised by the program?-Status: SUCCESS-Description: Exception -01476 was raised.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top