Datenbanken und Unit- / Integrationstests

25

Ich habe mit jemandem eine Diskussion über Unit- / Integrationstests mit Webanwendungen geführt und bin mir in Bezug auf eine Kernidee nicht einig. Das Problem ist, dass die Person, mit der ich spreche, der Meinung ist, dass die Datenbank, von der die Unit-Tests ausgeführt wurden, bereits Daten enthält, die vor und nach der Ausführung der Tests vollständig leer sein sollten.

Mein Anliegen bei vorab ausgefüllten Daten in der Datenbank ist, dass es keine Möglichkeit gibt, sicherzustellen, dass die Daten in einem guten Zustand gehalten werden. Die Tests selbst werden Daten in der Datenbank erstellen, löschen und ändern, sodass ich wirklich nicht sehe, wie gut es ist, Daten in der Datenbank zu haben, bevor Sie mit den Tests beginnen.

Dies scheint der beste Weg zum Testen der Datenbankfunktionalität zu sein:

  1. In einer "Setup" -Phase vor dem eigentlichen Test schneiden Sie zuerst alle Tabellen in der Datenbank ab
  2. Anschließend fügen Sie alle Daten ein, die für die Testfälle benötigt werden, die Sie ausführen möchten
  3. Anschließend führen Sie die Testfälle aus und validieren sie
  4. Dann kürzen Sie in einer "Teardown" -Phase erneut alle Tabellen in der Datenbank

Ich sehe keinen besseren Weg, um sicherzustellen, dass die Daten, mit denen Sie testen, gut testbar sind.

Vermisse ich hier etwas? Ist dies nicht der beste Weg, um datenbankbezogene Funktionen zu testen? Gibt es einen Vorteil, wenn die Datenbank bereits ausgefüllt ist und immer in der Datenbank vorhanden ist (noch bevor Sie mit den Tests beginnen oder nachdem die Tests durchgeführt wurden)? Jede Hilfe in Ideen, um meinen Prozess anders zu erklären, um meinen Standpunkt besser zu vermitteln, wäre auch großartig (wenn mein Standpunkt Vorteile hat).

Ryanzec
quelle
siehe auch: Software Testing Techniques
gnat

Antworten:

21

Unit-Tests sollten sich für mich nicht mit der Datenbank befassen, Integrationstests mit der Datenbank.

Integrationstests, die sich mit der Datenbank befassen, sollten in der Praxis eine leere Datenbank mit einem Auf- und Abbau-Ansatz haben. Die Verwendung eines transaktionsbasierten Ansatzes ist ein guter Weg, um eine Transaktion beim Einrichten und ein Rollback beim Auf- und Abbau zu erstellen.

Ihr Freund hört sich so an, als würde er einen Test unter dem Gesichtspunkt der "Regression" durchführen, dh reale Daten haben und sehen, wie das System reagiert, schließlich ist kein System perfekt, und es können normalerweise schlechte Daten irgendwo herumliegen, die Daten liefern einige Macken zu Ihrem Domain-Modell.

Ihre Best Practices sind der richtige Weg. Wenn ich ein Szenario für schlechte Daten finde, schreibe ich einen Integrationstest mit einem Setup und reiße dieses Szenario ab.

Nicholas Mayne
quelle
Ich mich bin nur sicher Note , was der Unterschied zwischen Unit - Tests und Integrationstests neben I - Einheit verspottet Daten verwendet , hören sollte und Integration sollte eine Datenbank verwenden (einen anderen Thread gestartet programmers.stackexchange.com/questions/101300/... , um herauszufinden , die Differenz ). Abgesehen davon scheint alles, was Sie sagen, mit dem übereinzustimmen, was ich denke.
Ryanzec
Kein Problem, ich habe mehr Informationen zu Ihrer anderen Antwort hinzugefügt
Nicholas Mayne
1
warum kannst du die DB nicht einmal testen? Wenn Sie Ihre SQL in gespeicherte Prozeduren einfügen, können Sie sie mit testdefinierten Daten Unit-testen, und plötzlich ist alles einfach. Dies ist definitiv eine bewährte
Methode,
1
integration tests- Was meinst du? Wie bereits erwähnt, können und sollten Module, die eine Datenbank verwenden , mit Unit-Tests getestet werden. Die Datenbank kann manuell verspottet oder durch eine In-Memory-Implementierung ersetzt werden
hellboy
6

Wenn Ihre Tests von der Datenbank abhängen, ist es meiner Meinung nach wichtiger, dass sich die Daten, die Sie interessieren, in einem bekannten Status für Ihre Tests befinden, als dass die Datenbank leer ist. Eine der Maßnahmen für gute Tests besteht darin, dass jeder Test aus einem Grund fehlschlagen sollte und kein anderer Test aus demselben Grund fehlschlagen sollte.

Wenn sich Ihre Tests also um den Status der Daten kümmern, versetzen Sie die Daten in diesen bekannten Status und setzen Sie sie nach dem Ausführen der Tests in diesen Status zurück, damit Ihre Tests reproduzierbar sind.

Wenn Sie Ihre Tests durch Verspotten vom Zustand der Daten entkoppeln können, wäre das auch eine gute Sache. Sie erwähnen, dass Sie Unit- / Integrationstests durchführen, aber diese beiden Dinge sollten natürlich getrennt betrachtet werden. Ihre Komponententests sollten nach Möglichkeit von der Datenbank entkoppelt werden, und Ihre Integrationstests sollten mit der Datenbank in einem bekannten Zustand getestet werden.

Paddyslacker
quelle
2

Nun, ich sehe einen Vorteil in einer vorab ausgefüllten Datenbank: Sie müssen nicht den Code schreiben, der die benötigten Daten einfügt, da diese vorhanden sind. Ansonsten gibt es nur Nachteile. Vielleicht hat jemand die Testdaten in der Datenbank geändert? Vielleicht hat jemand versucht, die Daten zu aktualisieren? Das Schlimmste ist jedoch, dass ein Testfall die Datenbank stark durcheinander bringt. Am Ende wird die gesamte Datenbank mehrmals manuell neu erstellt.

Sie haben Recht damit, wie Tests geschrieben werden sollten, mit der Ausnahme, dass ich nichts abschneiden würde:

  • Einrichtungsphase: Stellen Sie eine Verbindung zur Datenbank her und fügen Sie die Daten ein
  • Laufphase
  • Abrissphase: Eingefügte Daten entfernen (abschneiden)

Dieses Szenario eignet sich hervorragend für Komponententests. Wenn man Daten sowohl für Unit- als auch für Integrationstests benötigt, hat sich herausgestellt, dass eine große Einrichtungsphase, die allen Testfällen gemeinsam ist (wir haben alle "Einfügungen" in einer statischen Methode zusammengefasst), ebenfalls sehr gut funktionieren kann. Es ist wie ein Mittelweg zwischen Ihrer Idee und der Idee Ihres Freundes. Der einzige Nachteil ist, dass Sie beim Hinzufügen einiger neuer Daten sehr vorsichtig sein müssen, um vorhandene Testfälle nicht zu beschädigen (aber wenn Sie wie bei uns zwei bis drei Zeilen pro Tabelle hinzufügen, sollte dies kein Problem sein).

Jalayn
quelle
Würde ich nicht lieber die Teile der Datenbank erstellen, die jeweils für den Test benötigt werden, als die Daten versehentlich auf eine Weise ändern zu lassen, die einen Fehler verursacht? Es scheint etwas zu sein, das verhindert werden kann, wenn sichergestellt werden muss, dass die Daten korrekt sind, wenn ein Test fehlschlägt.
Ryanzec
1
Die umfangreiche Einrichtungsphase, in der für verschiedene Testfälle nützliche Daten eingefügt werden, ist möglicherweise nur für Integrationstests hilfreich, bei denen Sie verschiedene Teile der Anwendung überprüfen müssen, die zusammenarbeiten. Es kann sich lohnen, diesen großen gemeinsamen Satz von "Einsätzen" zu haben, da Sie höchstwahrscheinlich einige von ihnen für andere Integrationstests benötigen. Andernfalls, wenn es sich nur um reine Komponententests handelt, bin ich absolut dafür, dass für jeden Testfall ein Datensatz eingefügt werden muss.
Jalayn
1

Ich denke, Sie müssen ein Beispiel mit Ihrem Kollegen eingrenzen und herausfinden, was sie genau bedeuten. Sie befinden sich möglicherweise beide auf derselben Seite.

Beispiel: Überprüfen der Kontotransaktionstabelle

  1. Möchten Sie die Anzeige dieser Tabelle nicht für einen Benutzer / ein Konto ohne Transaktionen testen?
  2. Testen Sie das Hinzufügen des ersten Datensatzes und prüfen Sie, ob Sie einen Saldo erstellen können.
  3. Erstellen Sie Datensätze, wenn bereits Datensätze vorhanden sind, und überprüfen Sie den laufenden Saldo und alle anderen Geschäftsregeln.
  4. Tabelle mit vorhandenen Datensätzen und allen anderen CRUD anzeigen.

Ob Sie dies erreichen, indem Sie die Schritte 1 und 2 ausführen oder mit einer Datenbank beginnen, die sich bereits in diesem Status befindet (Sicherung wiederherstellen?), Ist nicht sicher, ob dies von Bedeutung ist. Ihre Idee, ein Skript für mich zu erstellen, erleichtert das Verwalten benötigter Änderungen (z. B. wenn Sie vergessen haben, ein Administratorkonto zu erstellen, und es für einen neuen Benutzer benötigen). Skriptdateien lassen sich einfacher in die Quellcodeverwaltung einbinden als einige Sicherungsdateien. Dies hängt auch davon ab, ob Sie diese App vertreiben oder nicht.

JeffO
quelle
0

Um Aspekte von ein paar Antworten zusammen zu ziehen und meine 2P hinzuzufügen ...

Hinweis: Meine Kommentare beziehen sich insbesondere auf Datenbanktests und nicht auf UI-Tests (obwohl dies offensichtlich ähnlich ist).

Datenbanken müssen genauso getestet werden wie Front-End-Anwendungen, werden jedoch in der Regel auf der Grundlage von "Funktioniert das mit dem Front-End?" Getestet. oder 'Erzielen die Berichte das richtige Ergebnis?', was meiner Meinung nach erst sehr spät im Prozess der Datenbankentwicklung getestet wird und nicht sehr robust ist.

Wir haben eine Reihe von Kunden, die zusätzlich zu den üblichen UAT / Performance / et al. Unit / Integration / Systemtests für ihre Data Warehouse-Datenbank verwenden. Tests. Sie stellen fest, dass sie mit einer kontinuierlichen Integration und automatisierten Tests viele Probleme lösen, bevor sie zur traditionellen UAT gelangen, wodurch sie Zeit in der UAT sparen und die Erfolgsaussichten für die UAT erhöhen.

Ich bin sicher, die meisten würden zustimmen, dass beim Testen von Datenbanken eine ähnliche Strenge angewendet werden sollte wie beim Testen von Frontends oder Berichten.

Das Wichtigste beim Testen ist das Testen kleiner einfacher Entitäten, um deren Richtigkeit sicherzustellen, bevor komplexe Kombinationen von Entitäten erstellt werden, um deren Richtigkeit sicherzustellen, bevor das System erweitert wird.

Geben Sie meiner Antwort einen Kontext ...

Unit Testing

  • hat einen Testfokus, um zu beweisen, dass das Gerät funktioniert, z. B. eine Tabelle, eine Ansicht, eine Funktion oder eine gespeicherte Prozedur
  • sollten die Schnittstellen "stubben", um externe Abhängigkeiten zu entfernen
  • stellt seine eigenen Daten zur Verfügung. Sie benötigen einen bekannten Anfangszustand der Daten. Wenn also die Möglichkeit besteht, dass Daten vor dem Test vorhanden sind, sollten vor dem Auffüllen Kürzungen / Löschungen vorgenommen werden
  • läuft im Idealfall in einem eigenen Ausführungskontext
  • wird nach sich selbst aufräumen und die verwendeten Daten entfernen; Dies ist nur wichtig, wenn Stichleitungen nicht verwendet werden.

Dies hat den Vorteil, dass Sie alle externen Abhängigkeiten vom Test entfernen und den geringsten Testumfang ausführen, um die Richtigkeit zu überprüfen. Offensichtlich können diese Tests nicht in der Produktionsdatenbank ausgeführt werden. Abhängig von der Art der Einheit können verschiedene Arten von Tests durchgeführt werden, darunter:

  • Schemaprüfung, einige nennen dies möglicherweise einen "Datenvertrag" -Test
  • Spaltenwerte durchlaufen
  • das Ausüben von logischen Pfaden mit unterschiedlichen Datenwerten für Funktionen, Prozeduren, Ansichten, berechnete Spalten
  • Edge-Case-Test - NULL, fehlerhafte Daten, negative Zahlen, zu große Werte

(Unit) Integrationstests

Ich fand diesen SE-Beitrag hilfreich, um über verschiedene Arten von Tests zu sprechen.

  • hat den Testfokus, um zu beweisen, dass Einheiten zusammenpassen
  • auf einer Reihe von Einheiten zusammen durchgeführt
  • sollten die Schnittstellen "stubben", um externe Abhängigkeiten zu entfernen
  • stellt seine eigenen Daten zur Verfügung, um die Auswirkungen externer Dateneinflüsse zu beseitigen
  • läuft im Idealfall in einem eigenen Ausführungskontext
  • wird nach sich selbst aufräumen und die erstellten Daten entfernen; Dies ist nur wichtig, wenn Stichleitungen nicht verwendet werden.

Beim Übergang von Komponententests zu diesen Integrationstests sind häufig etwas mehr Daten vorhanden, um eine größere Vielfalt von Testfällen zu testen. Offensichtlich können diese Tests nicht in der Produktionsdatenbank ausgeführt werden.

Anschließend werden Systemtests , Systemintegrationstests (auch als End-2-End-Tests bezeichnet) mit zunehmendem Datenvolumen und zunehmendem Umfang durchgeführt. Alle diese Tests sollten Teil eines Regressionstest-Frameworks werden. Einige dieser Tests werden möglicherweise von den Benutzern ausgewählt, die im Rahmen der UAT durchgeführt werden sollen, aber die UAT sind die von den Benutzern definierten Tests , nicht die von der IT definierten - ein häufiges Problem!

Nun habe ich einen Kontext angegeben, um Ihre eigentlichen Fragen zu beantworten

  • Das Vorbelegen von Daten für Unit- und Integrationstests kann zu falschen Testfehlern führen und sollte vermieden werden.
  • Die einzige Möglichkeit, konsistente Tests sicherzustellen, besteht darin, keine Annahmen über die Quelldaten zu treffen und diese genau zu kontrollieren.
  • Ein separater Testausführungskontext ist wichtig, um sicherzustellen, dass ein Tester nicht mit einem anderen Tester in Konflikt steht, der dieselben Tests auf einem anderen Zweig des Quellcode-gesteuerten Datenbankcodes ausführt.
Marcus D
quelle
-3

Ehrlich gesagt denke ich, wenn Sie Komponententests ohne eine Datenbank durchführen, die ungefähr die gleiche Größe wie die vorhandene Produktionsdatenbank hat, werden Sie viele Dinge haben, die die Tests bestehen und die Leistung in der Produktion beeinträchtigen. Natürlich bin ich auch aus diesem Grund gegen die Entwicklung einer winzigen lokalen Datenbank.

Und wenn der Code datenspezifisch ist, wie können Sie ihn ohne Daten effektiv testen? Sie werden nicht sehen, ob die Abfragen die richtigen Ergebnisse geliefert haben. Warum sollten Sie überhaupt in Betracht ziehen, eine leere Datenbank zu testen? Alles, was Sie wissen müssen, ist, ob die Syntax korrekt ist, und nicht, ob die Abfrage korrekt ist. Das kommt mir kurzsichtig vor. Ich habe zu viel Zeug gesehen, das läuft und Tests besteht, die kategorisch falsch sind. Wollen Sie das nicht in Unit-Tests finden? Ich mache.

HLGEM
quelle
Ich schlage nicht vor, auf eine leere Datenbank zuzugreifen, wenn Sie Schritt 2 sehen: "Dann fügen Sie alle Daten ein, die für die Testfälle benötigt werden, die Sie ausführen möchten." In Bezug auf das Leistungsproblem denke ich nicht, dass Unit-Tests das Ziel von Load-Tests sind. Komponententests zu mir es zu testen, um sicherzustellen, dass die Logik in Ihrem Code funktioniert. Wenn die Logik funktioniert, wird sie für 1 Datensatz oder 100.000.000.000 Datensätze mit denselben Basisdaten funktionieren (obwohl dies viel langsamer sein wird).
Ryanzec
Bei Datenbankabfragen geht es nicht nur um das Logische. Je früher Sie herausfinden, dass es in prod nicht funktioniert, desto besser. Was für eine Aufnahme oft funktioniert, wird bei der Produktion eine Zeitüberschreitung aufweisen und der Komponententest sollte dies so schnell wie möglich anzeigen.
HLGEM
Unit- und Integrationstests dienen der Funktionalität und nicht der Leistung, sodass Sie mit kleinen Datenmengen testen können
user151019
Unit-Tests sollten niemals eine Datenbank verwenden - Integrationstests verwenden Datenbanken.
Nicholas Mayne
1
Worüber Sie tatsächlich sprechen, ist das Testen der Last. Wenn Sie eine Reihe von Akzeptanztests haben und diese in ein Lasttest-Tool einbinden, können Sie den gewünschten Effekt erzielen.
Nicholas Mayne