Unit-Test von Stored Procedures

44

Ich habe jetzt schon ziemlich lange darüber nachgedacht.

Die grundlegende Frage lautet: Wie werden gespeicherte Prozeduren einem Komponententest unterzogen?

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). Aber wenn ich ein Beispiel aus dem wirklichen Leben betrachte, bei dem eine Zeile scheinbar einfach irgendwo eingefügt wird und einige Trigger dies und das vor oder nach dem Einfügen ausführen, ist es ziemlich schwierig, selbst die Grenzen einer "Einheit" zu definieren. Soll ich nur das INSERTselber testen ? Das ist ziemlich einfach, denke ich - mit relativ geringem Wert. Soll ich das Ergebnis der gesamten Ereigniskette testen? Abgesehen von der Frage, ob es sich um einen Komponententest handelt oder nicht, kann das Entwerfen eines geeigneten Tests eine ziemlich anstrengende Aufgabe sein, wobei viele zusätzliche Fragezeichen auf dem Weg entstehen.

Und dann kommt das Problem, dass sich Daten ständig ändern. Bei einer UPDATEBeeinflussung von mehr als nur wenigen Zeilen muss jede potenziell betroffene Zeile 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 Eine weitere kleine Frage, basierend auf Alex Kusnetsovs Antwort: Oder gibt es eine Schwelle, unter der es völlig nutzlos ist?

dezso
quelle

Antworten:

32

Wir machen das seit fast fünf Jahren und wir denken, dass explizites 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 mindestens einige der Testdaten aufzubauen und zu überprüfen, ob unsere Auswahl die erwarteten Ergebnisse liefert.

Ich habe einen Artikel mit dem Titel Diese Lücken schließen: 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, bei der es völlig hoffnungslos wird?" Benötigen komplexe Module viel mehr Tests als nur einfache.

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

AK
quelle
15

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 Unit-Tests schreiben, die die Prozedur für verschiedene Eingaben auswerten. 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, den das Gerät hat, sollte überprüft werden.

Sie haben Recht, dass das Entwerfen von Einheitentests einige Arbeit erfordert, aber der größte Teil dieser Arbeit muss zum manuellen Testen der Einheit ausgeführt werden. Sie sparen lediglich die zum Testen der Einheit erforderliche Arbeit, damit das Testen bei zukünftigen Änderungen durchgeführt wird kann genauso gründlich und deutlich einfacher sein.

Das Ändern von Daten erschwert das Testen, macht es jedoch nicht weniger wichtig und erhöht den Wert des Einheitentests, da die meisten Schwierigkeiten nur einmal durchdacht werden müssen und nicht jedes Mal, wenn eine Änderung an der Einheit vorgenommen wird. Gespeicherte Datensätze, Einfügungen / Aktualisierungen / Löschungen, die Teil des Setups / Herunterfahrens 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 im oberen oder unteren Bereich, die Sie vom Testen oder Unit-Testen abhalten könnte. Betrachten Sie diese Fragen:

  1. Schreiben Sie immer fehlerfreien Code?
  2. Sind kleine Einheiten immer fehlerfrei?
  3. Ist es in Ordnung, wenn eine große Einheit einen Bug hat?
  4. Wie viele Bugs sind nötig, 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 Anwendung wurde von einem Mitarbeiter geschrieben und gepflegt, an den sich noch niemand erinnert. Die Geräte haben eine Dokumentation, die das normale erwartete Verhalten beschreibt, aber sonst wenig. Welche davon würden Sie lieber finden?

  • Keine Komponententests in der Anwendung. Nachdem Sie die Änderung vorgenommen haben, können Sie einige manuelle Tests am Gerät selbst durchführen, um sicherzustellen, dass es weiterhin die in der Dokumentation erwarteten Werte zurückgibt. Sie können es dann auf die Produktion ausrollen, 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 beeinflussen) oder viel Zeit damit verbringen, zu lernen, wie die gesamte Anwendung funktioniert funktioniert so, dass Sie jedes Gerät 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 deren erwartete Reaktion, sondern auch abnormale Werte und die erwarteten Ausnahmen, die ausgelöst werden. Sie nehmen Ihre Änderung vor und führen die Komponententestsuite für die Anwendung sofort aus. Dabei stellen Sie fest, dass drei andere Einheiten nicht mehr die erwarteten Ergebnisse liefern. Zwei von ihnen sind harmlos, deshalb müssen Sie die Komponententests anpassen, um dies zu berücksichtigen. Der dritte erfordert einen weiteren leichten Tweak und einen kleinen neuen Unit-Test. Nachdem Sie die Änderungen vorgenommen haben, ist die gesamte Testsuite erfolgreich, und Sie führen die Änderung mit Zuversicht durch.
Leigh Riffel
quelle
1
Erstens danke für Ihre Antwort - ich habe keine weiteren Fortschritte in dieser Frage erwartet ... Zweitens muss ich zugeben, dass Sie mit den einfachen Operationen Recht haben: Selbst ein zweispaltiges INSERT kann einen Fehler erzeugen. Wenn es so geschrieben ist, dass die Spaltenreihenfolge mit den Argumenten abgeglichen werden kann, ist es vielleicht in Ordnung, aber Sie haben wieder Recht: Es ist wahrscheinlich besser, die gesamte App im Testmodus zu halten.
Dezso
@dezso Es ist eine großartige Frage und ein Konzept, das in der Datenbankwelt viel mehr Aufmerksamkeit erfordert.
Leigh Riffel
"Sie sollten die gesamte Ereigniskette als Einheit testen" - das ist das Gegenteil von Intuitivität. Es ist keine Einheit, wenn das der Fall ist. Sie führen Integrationstests durch
Joe Phillips,
@ Joe Philips - Nennen Sie es so, wie Sie möchten, und stellen Sie sicher, dass eine Prozedur, die eine Einfügung ausführt und ein paar Trigger auslöst, die erforderlichen automatischen Tests ausführt.
Leigh Riffel
8

Schauen Sie sich für PostgreSQL pgTAP an :

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

Frank Heikens
quelle
Gesehen, danke. Hat jemand Erfahrung damit?
Dezso
Ja, heutzutage gibt es einige Leute. Abonnieren Sie die Mailingliste, wenn Sie Fragen haben.
Theorie
6

Wenn Sie es vorziehen, die gespeicherten Prozeduren vollständig in SQL zu testen, besuchen Sie http://tsqlt.org/.

Es ist kompatibel mit MS SQL 2005 SP2 und höher, und der Vorteil ist, dass die Entwickler keine Kenntnisse in C # oder einer anderen Sprache benötigen, um die Tests zu implementieren.

Es gibt auch die Möglichkeit, Tabellen und Ansichten zu verspotten, um eine wieder ausführbare Testsuite zu erhalten.

Alain King
quelle