2009-10-07 4 views
16

Ich versuche, DBUnit mit JDBC und HSQLDB zu verwenden, und kann es nicht richtig zum Laufen bringen - obwohl ich früher mit großem Erfolg DBUnit mit Hibernate verwendet habe. Hier ist der Code:Wie kann ich mit DBUnit mit JDBC und HSQLDB testen, ohne dass eine NoSuchTableException auftritt?

import java.sql.PreparedStatement; 
import org.dbunit.IDatabaseTester; 
import org.dbunit.JdbcDatabaseTester; 
import org.dbunit.dataset.IDataSet; 
import org.dbunit.dataset.xml.XmlDataSet; 
import org.junit.Test; 

public class DummyTest { 

    @Test 
    public void testDBUnit() throws Exception { 
     IDatabaseTester databaseTester = new JdbcDatabaseTester("org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem", "sa", ""); 
     IDataSet dataSet = new XmlDataSet(getClass().getResourceAsStream("dataset.xml")); 
     databaseTester.setDataSet(dataSet); 
     databaseTester.onSetup(); 
     PreparedStatement pst = databaseTester.getConnection().getConnection().prepareStatement("select * from mytable"); 
    } 
} 

Und das ist die dataset.xml in Frage:

<dataset> 
    <table name="mytable"> 
     <column>itemnumber</column> 
     <column>something</column> 
     <column>other</column> 
     <row> 
      <value>1234abcd</value> 
      <value>something1</value> 
      <value>else1</value> 
     </row> 
    </table> 
</dataset> 

Dieser Test gibt mir ein NoSuchTableException:

org.dbunit.dataset.NoSuchTableException: mytable 
    at org.dbunit.database.DatabaseDataSet.getTableMetaData(DatabaseDataSet.java:282) 
    at org.dbunit.operation.DeleteAllOperation.execute(DeleteAllOperation.java:109) 
    at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79) 
    at org.dbunit.AbstractDatabaseTester.executeOperation(AbstractDatabaseTester.java:190) 
    at org.dbunit.AbstractDatabaseTester.onSetup(AbstractDatabaseTester.java:103) 
    at DummyTest.testDBUnit(DummyTest.java:18) 

Wenn ich entfernen Sie die databaseTester.onSetup () Linie, ich bekomme stattdessen eine SQLException:

java.sql.SQLException: Table not found in statement [select * from mytable] 
    at org.hsqldb.jdbc.Util.throwError(Unknown Source) 
    at org.hsqldb.jdbc.jdbcPreparedStatement.<init>(Unknown Source) 
    at org.hsqldb.jdbc.jdbcConnection.prepareStatement(Unknown Source) 
    at DummyTest.testDBUnit(DummyTest.java:19) 

Der Datensatz an sich arbeitet, da ich es es sollte wie zugreifen:

ITable table = dataSet.getTable("mytable"); 
String firstCol = table.getTableMetaData().getColumns()[0]; 
String tName = table.getTableMetaData().getTableName(); 

Was ich hier fehlt?

BEARBEITEN: Wie @mlk darauf hinweist, erstellt DBUnit keine Tabellen. Wenn ich folgendes vor dem Hinzufügen des Datensatzes einzufügen, geht alles glatt:

PreparedStatement pp = databaseTester.getConnection().getConnection().prepareStatement(
    "create table mytable (itemnumber varchar(255) NOT NULL primary key, " 
    + " something varchar(255), other varchar(255))"); 
pp.executeUpdate(); 

gab ich eine Followup Frage Is there any way for DBUnit to automatically create tables from a dataset or dtd?

Antwort

19

DBUnit keine Tabellen erstellen. Noch konnte es mit den begrenzten Informationen in der XML-Datei gegeben werden. Hibernate glaube ich kann die Tabellen erstellen.

Dies ist einer der Gründe, warum ich die Verwendung von In-Memory-Datenbanken eingestellt habe und stattdessen den DBA dazu gebracht habe, jedem Entwickler eine eigene Datenbank zu geben. Jeder Entwickler hält die Datenbank dann mit den gleichen Skripten auf dem neuesten Stand, die später live laufen. Das bringt einen kleinen Overhead mit sich (alle Entwickler müssen ihre Datenbanken auf dem neuesten Stand halten), bedeutet aber, dass Sie sich nicht um die Erstellung der Datenbank für jeden Lauf kümmern müssen, und Sie können sicher sein, dass die Abfragen in Echtzeit ausgeführt wurden.

Der zweite Grund war die Geschwindigkeit. Ich fand das Erstellen der In-Memory-Datenbank dauerte viel länger als einfach eine Verbindung zu einer vorhandenen Datenbank.

Der dritte Grund war der Abriss ist nicht-destruktiv (Start wischt die Datenbank). Das bedeutet, dass ich das zu testende SQL in der Datenbank ausführen kann, um herauszufinden, warum ein Test fehlschlägt.


aktualisieren: 20171115

Ich habe seit geschaltet JUnit rules that start up a real instance of the database server und so etwas wie FlywayDB zur Verwendung der Datenbank (und unter Verwendung der gleiche Skripte in Live wie im Test, mit der Anwendung verantwortlich für Gebäude zu bauen die Datenbank). Es ist deutlich langsamer als eine vordefinierte Datenbank. Wenn Sie jedoch gut definierte Microservices verwenden (und so die zu testende Funktionalität reduzieren) und sehr eng darüber sind, welche Tests eine Datenbank enthalten, können Sie solche Probleme migrieren und die Vorteile einer lokalen Datenbank nutzen, die immer mit der aktuellen übereinstimmt.

Es bedeutet leider, dass der Testabbau immer zerstörerisch ist, aber ein gut platzierter Bruchpunkt löst das.

+0

Ich habe eingeschaltet jetzt zu einer lokalen Oracle XE-Instanz in einer VM laufen. Der Grund dafür ist, dass wir uns weiterentwickeln können, wenn keine Verbindung zum internen Netzwerk besteht. –

+3

Mit einer In-Memory-Datenbank kann ich Komponententests überall ausführen, ohne eine Konfiguration umstellen zu müssen und ohne einen DB-Server starten zu müssen. In erster Linie laufen sie auf verschiedenen Dev-Boxen und auf dem CI-Server. Das ist ein großer Vorteil in meinem Buch. – Spencer

+0

Ja ist es. Ich persönlich fand es deutlich langsamer, aber das könnte sich jetzt geändert haben. Die Zeit, die zum Starten einer lokalen VM-Oracle XE-Instanz benötigt wird, ist ein kurzes, einmal tägliches Ereignis. –

0

Wenn Sie Ihre Tabellen im Voraus wie vorgeschlagen here erstellen und immer noch eine NoSuchTableException erhalten, dann stimmt etwas nicht mit dem Schema. Bevor Sie jetzt verrückt drehen, in allen Arten von seltsamen und wunderbaren Wege, damit das Hantieren, versuchen, das Schema Parameter PUBLIC Einstellung, wenn Sie die IDatabaseConnection erstellen, etwa so:

IDatabaseConnection databaseConnection = new HsqldbConnection(sqlConnection, "PUBLIC"); 

Es dauerte einige mich Schreiten durch die DbUnit Code mit dem Debugger, aber dies scheint den Trick zu tun.

4

... einige Jahre später haben wir jetzt bessere Möglichkeiten

Frühlings-Boot/Frühjahr JDBC eine Datenbank mit einfachen JDBC initialisieren.

Spring JDBC verfügt über eine Initialisierungsfunktion für DataSource. Spring Boot aktiviert standardmäßig und lädt SQL von den Standardpositionen schema.sql und data.sql (im Stammverzeichnis des Klassenpfads). Zusätzlich wird Spring Boot laden die schema-${platform}.sql und data-${platform}.sql Dateien (wenn vorhanden), wo Plattform ist der Wert spring.datasource.platform, z. Sie könnten es auf den Herstellernamen der Datenbank setzen (Hsqldb, H2, Oracle, MySQL, Postgresql usw.).

https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html

Verwandte Themen