it-swarm.com.de

Unit-Test von gespeicherten Prozeduren

Ich habe jetzt schon ziemlich lange darüber nachgedacht.

Die grundlegende Frage lautet: Wie werden gespeicherte Prozeduren getestet?

Ich sehe, dass ich Unit-Tests für Funktionen im klassischen Sinne relativ einfach einrichten kann (ich meine, sie erhalten null oder mehr Argumente und geben einen Wert zurück). Wenn ich jedoch ein reales Beispiel für eine scheinbar einfache Prozedur betrachte, bei der irgendwo eine Zeile eingefügt wird, wobei einige Auslöser dies und das vor oder nach dem Einfügen tun, ist es ziemlich schwierig, selbst die Grenzen einer 'Einheit' zu definieren. Sollte ich nur das INSERT selbst testen? Das ist ziemlich einfach, denke ich - mit relativ geringem Wert. Soll ich das Ergebnis der gesamten Ereigniskette testen? Abgesehen von der Frage, ob dies ein Komponententest ist oder nicht, kann das Entwerfen eines geeigneten Tests eine ziemlich anstrengende Aufgabe sein, da viele zusätzliche Fragezeichen auf dem Weg entstehen.

Und dann kommt das Problem, dass sich die Daten ständig ändern. Im Fall eines UPDATE, das mehr als nur einige Zeilen betrifft, muss jede potenziell betroffene Zeile irgendwie in die Testfälle einbezogen werden. Weitere Schwierigkeiten mit DELETEs und so weiter und so fort.

Wie testen Sie Ihre gespeicherten Prozeduren? Gibt es eine Schwelle in der Komplexität, wo es völlig hoffnungslos wird? Welche Ressourcen werden für die Wartung benötigt?

EDIT Noch eine kleine Frage, basierend auf AlexKuznetsovs Antwort: Oder gibt es eine Schwelle, unter der sie völlig nutzlos ist?

44
dezso

Wir machen das seit fast fünf Jahren und wir denken, dass das explizite Testen von Modifikationen definitiv machbar ist, aber es ist ziemlich langsam. Außerdem können wir solche Tests nicht einfach über mehrere Verbindungen gleichzeitig ausführen, es sei denn, wir verwenden separate Datenbanken. Stattdessen sollten wir Modifikationen implizit testen - wir verwenden sie, um zumindest einige der Testdaten aufzubauen und um sicherzustellen, dass unsere Auswahl die erwarteten Ergebnisse zurückgibt.

Ich habe einen Artikel mit dem Titel Schließen Sie diese Lücken: Lehren aus Unit-Testing T-SQL sowie einige Blog-Beiträge geschrieben

In Bezug auf Ihre Frage "Gibt es eine Schwelle in der Komplexität, wo es völlig hoffnungslos wird?", Benötigen komplexe Module viel mehr Tests als einfache.

Um die Wartung zu vereinfachen, generieren wir erwartete Ergebnisse und speichern sie in separaten Dateien - das macht einen großen Unterschied.

32
A-K

Ja, Sie sollten die gesamte Ereigniskette als Einheit testen. In Ihrem Beispiel mit einer Prozedur, die in eine Tabelle eingefügt wird und mehrere Trigger auslöst, sollten Sie Komponententests schreiben, die die Prozedur für verschiedene Eingaben bewerten. Jeder Komponententest sollte bestanden oder nicht bestanden werden, je nachdem, ob er die richtigen Werte zurückgibt, den Status von Tabellen korrekt ändert, die richtige E-Mail erstellt und sogar die richtigen Netzwerkpakete sendet, wenn er dafür ausgelegt ist. Kurz gesagt, jeder Effekt des Geräts sollte überprüft werden.

Sie haben Recht, dass das Entwerfen von Komponententests einige Arbeit erfordert, aber der größte Teil dieser Arbeit muss erledigt werden, um die Einheit manuell zu testen. Sie speichern nur die Arbeit, die zum Testen der Einheit erforderlich ist, damit bei einer Änderung in der Zukunft die Tests durchgeführt werden kann genauso gründlich und deutlich einfacher sein.

Das Ändern von Daten erschwert zwar das Testen, macht das Testen jedoch nicht weniger wichtig und erhöht den Wert des Komponententests, da die meisten Schwierigkeiten nur einmal durchdacht werden müssen und nicht jedes Mal, wenn eine Änderung am Gerät vorgenommen wird. Gespeicherte Datensätze, Einfügungen/Aktualisierungen/Löschungen, die Teil des Setups/Teardowns sind, und Operationen mit engem Umfang können verwendet werden, um dies zu vereinfachen. Da die Frage nicht datenbankspezifisch ist, variieren die Details.

Es gibt keine Komplexitätsschwelle am oberen oder unteren Ende, die Sie vom Testen oder vom Testen von Einheiten abhalten könnte. Betrachten Sie diese Fragen:

  1. Schreiben Sie immer fehlerfreien Code?
  2. Sind kleine Einheiten immer fehlerfrei?
  3. Ist es für eine große Einheit in Ordnung, einen Fehler zu haben?
  4. Wie viele Fehler sind erforderlich, um eine Katastrophe auszulösen?

Angenommen, Sie starten einen neuen Job und müssen eine Optimierung für eine kleine Funktion vornehmen, die an vielen Stellen verwendet wird. Die gesamte Bewerbung wurde von einem Mitarbeiter geschrieben und gepflegt, an den sich niemand erinnert. Die Einheiten verfügen über eine Dokumentation, die das normale erwartete Verhalten beschreibt, aber sonst wenig. Welche davon würden Sie lieber finden?

  • Keine Unit-Tests irgendwo in der Anwendung. Nach der Änderung können Sie einige manuelle Tests am Gerät selbst durchführen, um sicherzustellen, dass es weiterhin die erwarteten Werte in der Dokumentation zurückgibt. Sie können es dann für die Produktion bereitstellen, die Daumen drücken und hoffen, dass es funktioniert (schließlich schreiben Sie immer fehlerfreien Code, und eine Optimierung in einer Einheit könnte niemals eine andere bewirken) oder viel Zeit damit verbringen, zu lernen, wie die gesamte Anwendung funktioniert funktioniert so, dass Sie jede Einheit direkt oder indirekt manuell testen können.
  • Unit-Tests in der gesamten Anwendung, die automatisch täglich oder bei Bedarf ausgeführt werden. Sie überprüfen nicht nur normale Eingabewerte und ihre erwartete Reaktion, sondern auch abnormale Werte und die erwarteten Ausnahmen, die ausgelöst werden. Sie nehmen Ihre Änderung vor und führen die Unit-Test-Suite für die Anwendung sofort aus, wobei Sie feststellen, dass drei andere Einheiten nicht mehr die erwarteten Ergebnisse zurückgeben. Zwei davon sind gutartig, daher optimieren Sie die Komponententests, um dies zu berücksichtigen. Der dritte erfordert eine weitere leichte Optimierung und einen kleinen neuen Komponententest. Nachdem Sie die Änderungen vorgenommen haben, ist die gesamte Testsuite erfolgreich und Sie führen die Änderung mit Zuversicht durch.
15
Leigh Riffel

Für PostgreSQL überprüfen Sie pgTAP :

pgTAP ist eine Reihe von Datenbankfunktionen, mit denen TAP-emittierende Komponententests einfach in psql-Skripten oder Testfunktionen im xUnit-Stil geschrieben werden können.

8
Frank Heikens

Wenn Sie es vorziehen, die gespeicherten Prozeduren vollständig unter SQL zu testen, schauen Sie sich http://tsqlt.org/ an

Es ist kompatibel mit MS SQL 2005 SP2 und höher. Der Vorteil besteht darin, dass die Entwickler C # oder eine andere Sprache nicht kennen müssen, um die Tests zu implementieren.

Es gibt auch Möglichkeiten, Mock-Tabellen und -Ansichten zu erstellen, um eine wieder ausführbare Testsuite zu erhalten.

6
Alain King

In der Praxis hat "Unit-Test" in SQL im Vergleich zum Wert tatsächlicher Funktionstests, bei denen die gespeicherte Prozedur oder Funktion wie vorgesehen ausgeführt und anschließend das Ergebnis überprüft wird, nur einen geringen Wert. Dies bedeutet häufig, dass die Tests auf nahezu produktionsähnlichen Daten und Systemen ausgeführt werden.

Unit-Tests können ein Problem, das in der Logik liegt, leicht beschönigen. Für sehr einfache Prozeduren und Funktionen, die nur sehr wenig Logik enthalten und nicht datenbankübergreifend sind, sind Komponententests in Ordnung. Der Goldstandard sollte Funktionstests sein. Es fällt mir schwer, beispielsweise einen Komponententest für einen Job zu schreiben, der komplexe Orchestrierungstests abwickelt, z. B. die Synchronisierung der Benutzersicherheit über mehrere Datenbanken hinweg.

Letztendlich erstellen Unit-Tests eine Menge Code - Code, der beibehalten werden muss - und bieten nicht den gleichen Wert wie ein Funktionstest, der tatsächlich das korrekte Ergebnis einer Prozedur oder einer Reihe von Prozeduren testet.

Durch das Schreiben von Funktionstests wird auch Code erstellt, der gepflegt werden muss, aber auch Code, den die meisten Entwickler und Datenbankadministratoren verstehen. Keine Straftat beabsichtigt, aber t-sqlt ist nicht so intuitiv zu bedienen und weist Mängel bei datenbankübergreifenden Verfahren auf - Mängel, die dazu führen, dass noch mehr Code generiert wird (Code, der beibehalten werden muss).

Weniger Code ist besser. Code, der wirkungsvoller ist, ist besser. Unit-Tests sind in der Entwicklerwelt beliebt und haben sich auch in der SQL-Entwicklungswelt etabliert. Wenn jedoch Ihre SQL-Prozedur zum Hinzufügen eines Benutzers zu einer Datenbank nicht funktioniert, ist es ziemlich einfach, einen Unit-Test dafür zu schreiben, der dies nicht tut offenbaren den Bruch.

Strenge Funktionstests, die ein Verfahren auf Herz und Nieren prüfen, sind die besten. Integrationstests für Jobs, die mit geschäftskritischen Daten umgehen, sind de rigueur.

0
RelativitySQL