Eine Computeranwendung, die in einer Datenbank gespeicherte Informationen verwendet, ist eine Datenbankanwendung. Die meisten Anwendungen benötigen heutzutage eine Datenbank, entweder in Form von Flat-File- oder relationalen Datenbanken, als integrierte oder eigenständige Programme. Einige Beispiele sind der Kontaktmanager in Ihrem E-Mail-Client, Webshops, Online-Telefonbuch usw.

Eine Datenbankanwendung besteht aus einer Datenbank (und kann Stored Procedures haben), einer Codeschicht (in einer Container-Anwendung) und einem grafischen Frontend. Das Testen einer solchen Anwendung als Ganzes ist eine sehr schwierige Aufgabe. Das Auffinden der Quelle eines Problems bei der Identifizierung kann bei so vielen Komponenten im Bild sehr zeitaufwendig sein. Viele Datenbankfelder werden nie in einer visuellen Oberfläche angezeigt und in einigen Fällen werden abgeleitete Werte angezeigt. Dies erschwert das manuelle Testen. Außerdem gibt es einfach keine Möglichkeit, alle Datenbankfelder visuell zu überprüfen und dies häufig zu tun, um Probleme zu identifizieren, bevor sie auftauchen. Daher führen wir wie immer automatisierte Unit-Tests der Datenbankoperationen durch!

Lassen Sie uns als Beispiel den Teil der Benutzerregistrierung einer Webanwendung betrachten. Ein neuer Benutzer erstellt ein Konto, indem er einen Benutzernamen, ein Kennwort und einige persönliche Informationen eingibt und ein Konto anlegt. Auf der Datenbankseite werden ein oder mehrere Datensätze eingefügt, um diesen neuen Benutzer zu registrieren. Zusätzlich zu den vom Benutzer eingegebenen Informationen werden auch einige andere Felder von der Anwendung eingegeben, wie z. B. Daten, Art des Benutzers usw. Diese Felder dürfen in keiner Oberfläche angezeigt werden, so dass eine visuelle Überprüfung dieses Teils nicht möglich ist. Außerdem ist eine einfache Funktion wie diese nicht immer auf dem Radar für Regressionstests bei jedem Release, und doch könnte eine kleine Änderung dazu führen, dass ein wichtiges Feld, das in Marketingberichten und Analysen verwendet wird, nicht in der Datenbank gesetzt wird. Erschwerend kommt hinzu, dass diese Berichte vielleicht nur vierteljährlich erstellt werden, so dass es Sie ziemlich hart trifft, wenn Sie herausfinden, dass Ihre Datenbankkomponente drei Monate lang nicht korrekt funktioniert hat. Um dies zu vermeiden, implementieren wir automatisierte Tests.

Wie testet man eine Datenbankanwendung?

Die Grundidee ist, die Anwendungsfunktion zu nutzen, um Dinge in die Datenbank zu schreiben und dann die in die Datenbank geschriebenen Werte durch Abfragen zu überprüfen. Die visuelle Überprüfung ist ein guter erster Schritt, aber sie reicht kaum aus. In einer Anwendung können die in die Datenbank geschriebenen Werte und die Abfragen dynamisch erstellt werden, es ist sehr schwierig, dies jedes Mal manuell zu testen. Testen bei Abschluss der Entwicklung oder sehr spät im Entwicklungslebenszyklus ist wenig sinnvoll, das Finden und Beheben von Problemen in diesem Stadium kann sehr teuer werden. Eine gute Strategie ist es, das Datenbank-Mapping, eingehende und ausgehende Daten, gespeicherte Prozeduren, Funktionen, Standard-Spaltenwerte usw. zu testen und diese Komponenten als Unit-Test zu verwenden. Ein Prozess, der ‘Test erstellen – Test – Fix – Test – Stop on Pass’ beinhaltet, ist also der richtige Ansatz.

Datenbanktests sollten in einer isolierten Umgebung durchgeführt werden – die Tests haben ihre eigenen Datenbanken. Ein Prozess (außer dem Test) sollte nicht in der Lage sein, die Datenbank zu verändern. Auf diese Weise kennen wir den Zustand der Datenbank und können uns auf die Ergebnisse der Tests verlassen. Jeder einzelne Testfall sollte nach sich selbst eine Bereinigung durchführen, den Zustand der Datenbank zurücksetzen, damit der nächste Test nicht von den Ergebnissen des vorherigen Tests beeinflusst wird.

Eine Computeranwendung, die in einer Datenbank gespeicherte Informationen verwendet, ist eine Datenbankanwendung. Die meisten Anwendungen benötigen heutzutage eine Datenbank, entweder in Form von Flat-File- oder relationalen Datenbanken, als integrierte oder eigenständige Programme. Einige Beispiele sind der Kontaktmanager in Ihrem E-Mail-Client, Webshops, Online-Telefonbuch usw. Eine Datenbankanwendung besteht aus einer Datenbank (und kann Stored Procedures haben), einer Codeschicht (in einer Container-Anwendung) und einem grafischen Frontend. Das Testen einer solchen Anwendung als Ganzes ist eine sehr schwierige Aufgabe. Das Auffinden der Quelle eines Problems bei der Identifizierung kann bei so vielen Komponenten im Bild sehr zeitaufwendig sein. Viele Datenbankfelder werden nie in einer visuellen Oberfläche angezeigt und in einigen Fällen werden abgeleitete Werte angezeigt. Dies erschwert das manuelle Testen. Außerdem gibt es einfach keine Möglichkeit, alle Datenbankfelder visuell zu überprüfen und dies häufig zu tun, um Probleme zu identifizieren, bevor sie auftauchen. Daher führen wir wie immer automatisierte Unit-Tests der Datenbankoperationen durch! Lassen Sie uns als Beispiel den Teil der Benutzerregistrierung einer Webanwendung betrachten. Ein neuer Benutzer erstellt ein Konto, indem er einen Benutzernamen, ein Kennwort und einige persönliche Informationen eingibt und ein Konto anlegt. Auf der Datenbankseite werden ein oder mehrere Datensätze eingefügt, um diesen neuen Benutzer zu registrieren. Zusätzlich zu den vom Benutzer eingegebenen Informationen werden auch einige andere Felder von der Anwendung eingegeben, wie z. B. Daten, Art des Benutzers usw. Diese Felder dürfen in keiner Oberfläche angezeigt werden, so dass eine visuelle Überprüfung dieses Teils nicht möglich ist. Außerdem ist eine einfache Funktion wie diese nicht immer auf dem Radar für Regressionstests bei jedem Release, und doch könnte eine kleine Änderung dazu führen, dass ein wichtiges Feld, das in Marketingberichten und Analysen verwendet wird, nicht in der Datenbank gesetzt wird. Erschwerend kommt hinzu, dass diese Berichte vielleicht nur vierteljährlich erstellt werden, so dass es Sie ziemlich hart trifft, wenn Sie herausfinden, dass Ihre Datenbankkomponente drei Monate lang nicht korrekt funktioniert hat. Um dies zu vermeiden, implementieren wir automatisierte Tests. Wie testet man eine Datenbankanwendung? Die Grundidee ist, die Anwendungsfunktion zu nutzen, um Dinge in die Datenbank zu schreiben und dann die in die Datenbank geschriebenen Werte durch Abfragen zu überprüfen. Die visuelle Überprüfung ist ein guter erster Schritt, aber sie reicht kaum aus. In einer Anwendung können die in die Datenbank geschriebenen Werte und die Abfragen dynamisch erstellt werden, es ist sehr schwierig, dies jedes Mal manuell zu testen. Testen bei Abschluss der Entwicklung oder sehr spät im Entwicklungslebenszyklus ist wenig sinnvoll, das Finden und Beheben von Problemen in diesem Stadium kann sehr teuer werden. Eine gute Strategie ist es, das Datenbank-Mapping, eingehende und ausgehende Daten, gespeicherte Prozeduren, Funktionen, Standard-Spaltenwerte usw. zu testen und diese Komponenten als Unit-Test zu verwenden. Ein Prozess, der 'Test erstellen - Test - Fix - Test - Stop on Pass' beinhaltet, ist also der richtige Ansatz. Datenbanktests sollten in einer isolierten Umgebung durchgeführt werden - die Tests haben ihre eigenen Datenbanken. Ein Prozess (außer dem Test) sollte nicht in der Lage sein, die Datenbank zu verändern. Auf diese Weise kennen wir den Zustand der Datenbank und können uns auf die Ergebnisse der Tests verlassen. Jeder einzelne Testfall sollte nach sich selbst eine Bereinigung durchführen, den Zustand der Datenbank zurücksetzen, damit der nächste Test nicht von den Ergebnissen des vorherigen Tests beeinflusst wird. Ein Datenbanktest besteht aus den folgenden Hauptschritten:  1. Daten-Setup - grundsätzlich lernt der Test hier die Datenbank kennen und kann so aus dem Testergebnis einen Pass/Fail-Status ableiten. Das Setup könnte so aufwändig sein wie das Erstellen der Datenbank, das Auffüllen mit Seed-Daten und das Laden von Testdaten oder wir könnten einfach, während kleinerer Testzyklen, Werte in einer Tabelle (oder alle Daten in einem bestimmten Kontext)  löschen (zurücksetzen). Mit diesem Schritt wird der Zustand der Datenbank eingerichtet und etabliert.  2. Testausführung - hier führen wir unsere Tests mit Hilfe eines Testframeworks wie DbUnit aus. Es gibt auch andere Datenbanktest-Tools, aber wir werden uns in diesem Artikel mit DbUnit beschäftigen.  3. Pass/Fail-Urteil - der Test entscheidet über das Ergebnis, indem er sich die Werte in den Datenbanktabellen ansieht. Test-Frameworks bieten einfache programmatische Möglichkeiten, dies zu tun, die viel besser funktionieren als die visuelle Inspektion. Lassen Sie uns nun einen schnellen Test mit DbUnit durchgehen. Ein einfacher Test erweitert die abstrakte Basisklasse DatabaseTestCase und implementiert die Methoden getConnection() und getDataSet(). getConnection stellt die Verbindung zur Datenbank her und getDataSet definiert die Daten, die wir bei Testabschluss erwarten. In diesem Blogeintrag finden Sie den Beispielcode und die Schritte. DbUnit bietet auch ordentliche Möglichkeiten, Ihre Daten in xml zu definieren und eine 'equals()' Methode, um Tabellen zu vergleichen. Und schließlich ein kurzer Absatz über die Verwendung von DbUnit und iBatis zum Aufbau eines flexiblen und skalierbaren Datenbank-Test-Frameworks. Ich entwickelte dieses Framework, um eine Anwendung zu testen, die Daten aus Dateien las und in verschiedene Datenbanken schrieb. Es gab keine Unit-Tests und wir waren weit über die Unit-Testing-Phase hinaus. Wir brauchten also funktionale End-to-End-Tests. Die eigentliche Herausforderung bestand darin, ein Framework zu bauen, bei dem die Tests leicht mit den (häufigen) Änderungen an Geschäftsregeln, Dateiformaten und Zieltabellen modifiziert werden konnten. Die Tests bestanden aus einer Testfallklassendatei und waren datengesteuert. Ein einzelner Testfall verwendete einen Satz von Eingabedatendateien, um die Datenbank zu laden und die Ergebnisse anhand eines anderen Satzes von Dateien mit erwarteten Ergebnismengen zu überprüfen. Das Teil, das den Testfall und die Datensätze verband, war iBatis. Die Verbindungsparameter und die Abfragen zum Einrichten der Datenbank für den Test und zum Überprüfen der Ergebnisse des Tests wurden in XML-Dateien definiert. Ein Test verwendete während der Ausführung zwei oder mehr XML-Dateien. Es wurde ein iBatis SQLMapClient unter Verwendung der XML-Datei "SQLMapConfig" erstellt und Datenbankoperationen auf Basis der Abfragen in den anderen XML-Dateien durchgeführt. iBatis erlaubt die Verwendung von einfachem SQL in den XML-Dateien. So konnten auch die Datenbankverantwortlichen problemlos Testfälle aktualisieren oder erstellen! Durch diese Kombination aus DbUnit und iBatis blieb das Framework sehr flexibel und Änderungen an den Geschäftsregeln oder der Applikation bedeuteten nicht, dass man ganze Testfälle löschen musste, sondern nur Änderungen an den XML-Konfigurationsdateien.
Testen von Datenbankanwendungen

Ein Datenbanktest besteht aus den folgenden Hauptschritten:
1. Daten-Setup – grundsätzlich lernt der Test hier die Datenbank kennen und kann so aus dem Testergebnis einen Pass/Fail-Status ableiten. Das Setup könnte so aufwändig sein wie das Erstellen der Datenbank, das Auffüllen mit Seed-Daten und das Laden von Testdaten oder wir könnten einfach, während kleinerer Testzyklen, Werte in einer Tabelle (oder alle Daten in einem bestimmten Kontext)
löschen (zurücksetzen). Mit diesem Schritt wird der Zustand der Datenbank eingerichtet und etabliert.
2. Testausführung – hier führen wir unsere Tests mit Hilfe eines Testframeworks wie DbUnit aus. Es gibt auch andere Datenbanktest-Tools, aber wir werden uns in diesem Artikel mit DbUnit beschäftigen.
3. Pass/Fail-Urteil – der Test entscheidet über das Ergebnis, indem er sich die Werte in den Datenbanktabellen ansieht. Test-Frameworks bieten einfache programmatische Möglichkeiten, dies zu tun, die viel besser funktionieren als die visuelle Inspektion.

Lassen Sie uns nun einen schnellen Test mit DbUnit durchgehen. Ein einfacher Test erweitert die abstrakte Basisklasse DatabaseTestCase und implementiert die Methoden getConnection() und getDataSet(). getConnection stellt die Verbindung zur Datenbank her und getDataSet definiert die Daten, die wir bei Testabschluss erwarten. In diesem Blogeintrag finden Sie den Beispielcode und die Schritte. DbUnit bietet auch ordentliche Möglichkeiten, Ihre Daten in xml zu definieren und eine ‘equals()’ Methode, um Tabellen zu vergleichen.

Und schließlich ein kurzer Absatz über die Verwendung von DbUnit und iBatis zum Aufbau eines flexiblen und skalierbaren Datenbank-Test-Frameworks. Ich entwickelte dieses Framework, um eine Anwendung zu testen, die Daten aus Dateien las und in verschiedene Datenbanken schrieb. Es gab keine Unit-Tests und wir waren weit über die Unit-Testing-Phase hinaus. Wir brauchten also funktionale End-to-End-Tests. Die eigentliche Herausforderung bestand darin, ein Framework zu bauen, bei dem die Tests leicht mit den (häufigen) Änderungen an Geschäftsregeln, Dateiformaten und Zieltabellen modifiziert werden konnten. Die Tests bestanden aus einer Testfallklassendatei und waren datengesteuert. Ein einzelner Testfall verwendete einen Satz von Eingabedatendateien, um die Datenbank zu laden und die Ergebnisse anhand eines anderen Satzes von Dateien mit erwarteten Ergebnismengen zu überprüfen. Das Teil, das den Testfall und die Datensätze verband, war iBatis. Die Verbindungsparameter und die Abfragen zum Einrichten der Datenbank für den Test und zum Überprüfen der Ergebnisse des Tests wurden in XML-Dateien definiert. Ein Test verwendete während der Ausführung zwei oder mehr XML-Dateien. Es wurde ein iBatis SQLMapClient unter Verwendung der XML-Datei “SQLMapConfig” erstellt und Datenbankoperationen auf Basis der Abfragen in den anderen XML-Dateien durchgeführt. iBatis erlaubt die Verwendung von einfachem SQL in den XML-Dateien. So konnten auch die Datenbankverantwortlichen problemlos Testfälle aktualisieren oder erstellen! Durch diese Kombination aus DbUnit und iBatis blieb das Framework sehr flexibel und Änderungen an den Geschäftsregeln oder der Applikation bedeuteten nicht, dass man ganze Testfälle löschen musste, sondern nur Änderungen an den XML-Konfigurationsdateien.