2010-09-24 7 views
31

Ich habe eine Anwendung, wo viele "Einheit" Tests eine echte Verbindung zu einer Oracle-Datenbank während ihrer Ausführung verwenden.Erstellen einer In-Memory-Datenbankstruktur aus einer Oracle-Instanz

Wie Sie sich vorstellen können, benötigen diese Tests zu viel Zeit, um ausgeführt zu werden, da sie einige Spring-Kontexte initialisieren und mit der Oracle-Instanz kommunizieren müssen. Darüber hinaus müssen wir komplexe Mechanismen wie Transaktionen verwalten, um Datenbankänderungen nach der Testausführung zu vermeiden (selbst wenn wir nützliche Klassen von Spring wie AbstractAnnotationAwareTransactionalTests verwenden).

Also meine Idee ist, diese Oracle-Test-Instanz schrittweise durch eine In-Memory-Datenbank zu ersetzen. Ich werde oder vielleicht besser h2 verwenden.

Meine Frage ist zu wissen, was der beste Ansatz ist, um das zu tun. Mein Hauptanliegen betrifft den Aufbau der In-Memory-Datenbankstruktur und das Einfügen von Referenzdaten.

Natürlich kann ich die Datenbankstruktur von Oracle extrahieren, verwenden einige Werkzeuge wie SQL Developer oder TOAD, und dann diese Skripte modifizieren sie an die hsqldb oder h2 Sprache anzupassen. Aber ich denke nicht, dass das der bessere Ansatz ist.


In der Tat, ich habe bereits, dass an einem anderen Projekt hsqldb, aber ich habe manuell alle Skripte geschrieben Tabellen zu erstellen. Glücklicherweise hatte ich nur wenige Tabellen zu erstellen. Mein Hauptproblem während dieses Schrittes war das "Übersetzen" der Oracle-Skripte, die zum Erstellen von Tabellen verwendet wurden, in die Sprache hsqldb.

Zum Beispiel kann eine Tabelle in Oracle mit dem folgenden SQL-Befehl erstellt:

CREATE TABLE FOOBAR (
    SOME_ID NUMBER, 
    SOME_DATE DATE, -- Add primary key constraint 
    SOME_STATUS NUMBER, 
    SOME_FLAG NUMBER(1) DEFAULT 0 NOT NULL); 

benötigt "übersetzt" für hsqldb werden:

CREATE TABLE FOOBAR (
    SOME_ID NUMERIC, 
    SOME_DATE TIMESTAMP PRIMARY KEY, 
    SOME_STATUS NUMERIC, 
    SOME_FLAG INTEGER DEFAULT 0 NOT NULL); 

In meinem aktuellen Projekt gibt es auch viele Tabellen, um das manuell zu tun ...


Also meine Fragen:

  • Was sind die Ratschläge können Sie mir geben, das zu erreichen?
  • Bietet h2 oder hsqldb einige Tools zum Generieren ihrer Skripts von einer Oracle-Verbindung?

Technische Informationen

Java 1.6, Spring 2.5, 10 Oracle.g, Maven 2


bearbeiten

Einige Informationen in Bezug auf meine Unit-Tests:

In der Anwendung, wo ich hsqldb verwendet, hatte ich die folgenden Tests: - Some "basic" Einheit Tests, die nichts mit DB zu tun haben. - Für DAO-Tests habe ich hsqldb verwendet, um Datenbankmanipulationen wie CRUD auszuführen. - Dann, auf der Service-Schicht, habe ich Mockito verwendet, um meine DAO-Objekte zu verspotten, um sich auf den Service-Test und nicht die ganzen Anwendungen (d. H. Service + dao + DB) zu konzentrieren.

In meiner aktuellen Anwendung haben wir das schlimmste Szenario: Die DAO-Layer-Tests müssen eine Oracle-Verbindung ausgeführt werden. Die Dienstebene verwendet nicht (noch) beliebige Mock-Objekte, um das DAO zu simulieren. So Dienste Tests auch benötigen eine Oracle-Verbindung.

Ich bin mir bewusst, dass Mocks und In-Memory-Datenbank zwei getrennte Punkte sind, und ich werde sie so schnell wie möglich ansprechen. Mein erster Schritt ist jedoch, versuchen, die Oracle-Verbindung durch eine In-Memory-Datenbank zu entfernen, und dann werde ich meine Mockito Kenntnisse verwenden, um die Tests zu verbessern.

Beachten Sie, dass ich Unit-Tests auch von Integrationstests trennen möchte. Letzteres benötigt einen Zugriff auf die Oracle-Datenbank, um "echte" Tests durchzuführen, aber mein Hauptanliegen (und das ist der Zweck dieser Frage) ist, dass fast alle meine Unit-Tests heute nicht isoliert ausgeführt werden.

Antwort

19

Verwenden Sie zum Testen eine In-Memory/Java-Datenbank. Dies stellt sicher, dass die Tests näher an der realen Welt liegen, als wenn Sie versuchen, die Datenbank in Ihrem Test zu "abstrahieren". Wahrscheinlich sind solche Tests auch einfacher zu schreiben und zu pflegen. Auf der anderen Seite, was Sie wahrscheinlich in Ihren Tests "abstrahieren" möchten, ist die Benutzeroberfläche, weil UI-Tests in der Regel schwer zu automatisieren sind.

Die Oracle-Syntax, die Sie gepostet haben, funktioniert gut mit der H2-Datenbank (ich habe es gerade getestet), also scheint H2 die Oracle-Syntax besser zu unterstützen als HSQLDB. Disclaimer: Ich bin einer der Autoren von H2. Wenn etwas nicht funktioniert, poste es bitte auf der H2-Mailingliste.

Sie sollten die DDL-Anweisungen für die Datenbank in Ihrem Versionskontrollsystem trotzdem haben. Sie können diese Skripts auch zum Testen verwenden. Möglicherweise müssen Sie auch mehrere Schemaversionen unterstützen - in diesem Fall könnten Sie Versionsaktualisierungsskripts schreiben (alter table ...). Mit einer Java-Datenbank können Sie diese auch testen.

Übrigens müssen Sie den In-Memory-Modus nicht unbedingt verwenden, wenn Sie H2 oder HSQLDB verwenden. Beide Datenbanken sind schnell, selbst wenn Sie die Daten beibehalten. Und sie sind einfach zu installieren (nur eine JAR-Datei) und benötigen viel weniger Speicher als Oracle.

+2

Da der DAO-Code eng mit Oracle gekoppelt ist und die DAO nicht abstrahiert werden kann, scheint dies der beste Ansatz zu sein - obwohl der DAO-Code hoffentlich nicht auf irgendwelche Oracle-Besonderheiten angewiesen ist. Am besten, die DAOs so schnell wie möglich zu abstrahieren ... –

2

Für was sind Ihre Komponententests? Wenn sie das ordnungsgemäße Funktionieren von DDLs und gespeicherten Prozeduren testen, sollten Sie die Tests "näher" an Oracle schreiben: entweder ohne Java-Code oder ohne Spring und andere nette Web-Interfaces, die sich auf die db konzentrieren.

Wenn Sie die in Java und Spring implementierte Anwendungslogik testen möchten, können Sie Mock-Objekte/Datenbankverbindung verwenden, um Ihre Tests von der Datenbank unabhängig zu machen.

Wenn Sie die Arbeit als Ganzes testen wollen (was gegen das modulare Entwicklungs- und Testprinzip ist), dann können Sie Ihre Datenbank virtualisieren und an dieser Instanz testen, ohne das Risiko irreparabler Änderungen zu haben.

+0

Ich habe meine Frage bearbeitet, um genauer zu sein, warum ich eine In-Memory-DB verwenden möchte. – romaintaz

4

Neueste HSQLDB 2.0.1 unterstützt ORACLE-Syntax für DUAL, ROWNUM, NEXTVAL und CURRVAL über ein Syntaxkompatibilitätsflag, sql.syntax_ora = true. Auf die gleiche Weise werden die Verkettung einer Zeichenfolge mit einer NULL-Zeichenfolge und Einschränkungen für NULL in UNIQUE-Einschränkungen mit anderen Flags behandelt. Die meisten ORACLE Funktionen wie TO_CHAR, TO_DATE, NVL etc. sind in der bereits gebaut

Im Moment einfach ORACLE-Typen verwendet werden, wie NUMBER können Sie eine Typdefinition verwenden.

CREATE TYPE NUMBER AS NUMERIC

Der nächste Schnappschuss erlaubt NUMBER (N) und andere Aspekte der ORACLE-Typ-Kompatibilität, wenn das Flag gesetzt ist.

Herunterladen von http://hsqldb.org/support/

[Update:] Der Snapshot am 4. Oktober ausgegeben übersetzt die meisten Oracle bestimmte Typen zu ANSI SQL-Typen. HSQLDB 2.0 unterstützt auch den ANSI-SQL-INTERVAL-Typ und die Datums-/Zeitstempelarithmetik genauso wie Oracle.

1

Solange Ihre Tests nach sich selbst bereinigen (wie Sie bereits wissen, wie eingerichtet wird), ist nichts falsch daran, Tests mit einer echten Datenbankinstanz durchzuführen. In der Tat ist es der Ansatz, den ich normalerweise bevorzuge, weil Sie etwas so produktionsnah wie möglich testen werden.

Die Inkompatibilitäten scheinen klein zu sein, enden aber nicht so lange danach. In einem guten Fall, können Sie mit einigen ekligen Übersetzung/umfangreiche Spott durchkommen. In schlechten Fällen werden Teile des Systems einfach nicht zu testen sein, was meiner Meinung nach ein inakzeptables Risiko für geschäftskritische Systeme darstellt.

+4

"* Es ist nichts falsch daran, Tests gegen eine echte DB * auszuführen". Dem stimme ich nicht zu. Die Verwendung einer echten DB für ** Einheit ** -Testen ist aus mindestens 2 Gründen keine gute Idee: 1. Ihr Test hängt von Ihrer DB ab und kann nur fehlschlagen, weil Ihre Datenbank ausgefallen ist. 2. Das Erstellen einer Verbindung zu einer realen DB ist teurer, und wenn Sie von hundert Tests sprechen, werden ihre Ausführungen ein Problem sein. Besonders auf TDD-Art. – romaintaz

+3

Natürlich ist es auch eine gute Idee, Tests zu haben, die auf eine echte Datenbank zugreifen, aber es handelt sich nicht um ** Unit ** Tests, sondern um ** Integrationstests. Und das war nicht mein Punkt hier. – romaintaz