Hintergrund des Themas
Die manuelle Überprüfung der Geschäftslogik in SQL (auf Ebene von gespeicherten Prozeduren, Funktionen, Triggern) führt zu Fehlern, die erst in der Produktion sichtbar werden. Lange Zeit war das Testen von SQL-Szenarien informell und nicht standardisiert. Die Entwicklung von CI/CD-Technologien erfordert jedoch automatisierte Tests auch für SQL-Code.
Problem
Die meisten Entwickler beschränken sich nur auf Tests auf Anwendungsebene. Das Fehlen von Prüfungen selbst für SQL-Prozeduren und -Funktionen führt zu Defekten, die von keinem Testpaket abgedeckt werden – zum Beispiel bei Änderungen der UDF-Logik oder Regressionen in Berichten.
Lösung
In den Arbeitsabläufen moderner Teams werden Unit- und Integrationstests direkt für SQL-Code organisiert. Für Unit-Tests werden Frameworks wie tSQLt (SQL Server), utPLSQL (Oracle), pgTAP (PostgreSQL) verwendet, und für Integrationstests separate Umgebungen eingerichtet, um temporäre Datenbanken zu verwenden, Migrationen anzuwenden und Geschäftsszenarien zu überprüfen.
Beispiel für einen Unit-Test mit pgTAP:
-- Überprüfung des Gehalts SELECT plan(2); SELECT is( (SELECT calc_salary(1)), 1000, 'Gehalt für Benutzer 1 korrekt' ); SELECT isnt( (SELECT calc_salary(2)), 0, 'Gehalt für Benutzer 2 ist nicht null' ); SELECT finish();
Code für einen Integrationstest in CI/CD:
psql -U user -d testdb < migrations.sql psql -U user -d testdb < test_data.sql psql -U user -d testdb -c "SELECT * FROM my_procedure_test();"
Wesentliche Merkmale:
Kann man sich nur mit automatisierten Tests auf Anwendungsebene behelfen, wenn die Prozeduren umfangreich sind? Nein, denn UI/API-Tests garantieren nicht die Korrektheit der SQL-Logik (zum Beispiel falsche Bedingungen innerhalb gespeicherter Funktionen oder Verletzungen bei der Datenaktualisierung). Unit-Tests sollten alle rituellen Verz branchungen im SQL-Code abdecken.
Reichen "manuelle" Ausführungen von Testskripten aus – schließlich gibt es nur wenige Änderungen in der Datenbank? Nicht ausreichend, selbst in kleinen Projekten treten Fehler nach Änderungen des Schemas oder der Logik auf. Die Automatisierung des Testens im CI-Prozess verringert den menschlichen Faktor und verhindert Regressionen.
Kann man nur "kritische" Prozeduren testen, den Rest auslassen? Der beste Ansatz besteht darin, maximal viele Funktionen abzudecken, insbesondere wenn der Code in Zukunft von mehreren Teams geändert wird: Nicht offensichtliche Berechnungen und Edge-Cases treten häufig in nicht-standardisierten Verzweigungen auf.
Bei der Überarbeitung der Rabattberechnungsprozedur wurden manuell einige Fälle getestet, die Hauptverzweigungen der Logik wurden jedoch ausgelassen. In der Produktion begannen die Kunden, falsche Rabatte zu erhalten, die Klärung dauerte mehrere Tage.
Vorteile:
Zeiteinsparung zu Beginn.
Nachteile:
Verluste durch manuelle Korrekturen, Unbequemlichkeit bei Überarbeitungen und Refactoring.
Es wurden Unit-Tests mit pgTAP für alle wichtigen UDFs und Prozeduren entwickelt, Integrationstests werden über CI bei jedem Merge des Branches ausgeführt. Fehler und Regressionen werden vor dem Deployment aufgedeckt.
Vorteile:
Stabilität der Funktionen, Möglichkeit, die Geschäftslogik schnell zu überarbeiten, minimale Fehler in der Produktion.
Nachteile:
Es ist ein Zeitaufwand erforderlich, um die Testdatenbank aufzubauen und zu warten.