2009-10-07 9 views
16

J'essaie d'utiliser DBUnit avec JDBC et HSQLDB, et je n'arrive pas à le faire fonctionner - même si j'ai déjà utilisé DBUnit avec Hibernate avec beaucoup de succès. Voici le code:Comment tester avec DBUnit avec JDBC simple et HSQLDB sans faire face à une exception NoSuchTableException?

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"); 
    } 
} 

Et voici la dataset.xml en question:

<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> 

Ce test me donne un 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) 

Si je supprime le databaseTester.onSetup () ligne, j'obtiens une SQLException à la place:

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) 

L'ensemble de données en lui-même fonctionne, puisque je peux y accéder comme il se doit:

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

Qu'est-ce que je manque ici?

EDIT: Comme l'indique @mlk, DBUnit ne crée pas de tables. Si j'insérer ce qui suit avant d'ajouter l'ensemble de données, tout se passe bien:

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

J'ai posté une question de suivi que Is there any way for DBUnit to automatically create tables from a dataset or dtd?

Répondre

19

DbUnit ne crée pas de tables. Il ne pourrait pas non plus avec l'information limitée donnée dans le fichier XML. Hibernate je crois peut créer les tables.

C'est l'une des raisons pour lesquelles j'ai arrêté d'utiliser des bases de données en mémoire et j'ai demandé à l'administrateur de base de données de donner à chaque développeur sa propre base de données. Chaque développeur maintient ensuite la base de données à jour en utilisant les mêmes scripts qui sont ensuite exécutés en direct. Cela ajoute une petite surcharge (tous les développeurs ont besoin de maintenir leurs bases de données à jour), mais cela signifie que vous n'avez pas besoin de créer la base de données pour chaque exécution et vous pouvez être sûr que les requêtes s'exécutent en live.

La deuxième raison était la vitesse. J'ai trouvé que la création de la base de données en mémoire prenait beaucoup plus de temps que la simple connexion à une base de données existante.

La troisième raison était que le démontage est non-destructif (démarrage de la base de données). Cela signifie que je peux exécuter le SQL sous test sur la base de données pour aider à déterminer pourquoi un test échoue.


Mise à jour: 20171115

J'ai depuis commencé à utiliser JUnit rules that start up a real instance of the database server et quelque chose comme FlywayDB pour construire la base de données (et en utilisant les mêmes scripts en direct comme dans l'essai, l'application responsable de la construction la base de données). Il est significativement plus lent que l'utilisation d'une base de données prédéfinie. Cependant, en utilisant des microservices bien définis (et donc en réduisant les fonctionnalités à tester) et en étant très strict sur les tests qui obtiennent une base de données, vous pouvez migrer de tels problèmes et obtenir les avantages d'une base de données locale.

Cela signifie que l'essai de démontage est toujours destructif, mais un point de rupture bien placé le résout.

+0

Je suis maintenant passé à une instance locale Oracle XE en cours d'exécution dans une machine virtuelle. La raison en est que nous pouvons continuer à développer lorsque nous ne sommes pas connectés au réseau interne. –

+3

Avec une base de données en mémoire, je peux exécuter des tests unitaires n'importe où, sans avoir à changer de configuration et sans avoir à démarrer un serveur de base de données. Principalement, ils fonctionnent sur différentes boîtes de dev et sur le serveur CI. C'est un énorme avantage dans mon livre. – Spencer

+0

Oui c'est. Personnellement, je l'ai trouvé beaucoup plus lent, mais cela a peut-être changé maintenant. Le temps nécessaire pour démarrer une instance VM'ed Oracle XE locale est une petite chose une fois par jour. –

0

Si vous créez vos tables à l'avance comme suggéré here et obtenez toujours une exception NoSuchTableException, alors il y a un problème avec le schéma. Avant maintenant tourner fou, tripotant dans toutes sortes de façons étranges et merveilleuses, essayez de régler le paramètre de schéma pour PUBLIC lorsque vous créez le IDatabaseConnection, comme ceci:

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

Il m'a fallu marcher à travers la DbUnit code avec le débogueur mais cela semble faire l'affaire.

4

... quelques années plus tard nous avons maintenant de meilleures options

Spring Boot/Spring JDBC peut initialiser une base de données avec JDBC simple.

Spring JDBC possède une fonction d'initialisation DataSource. Spring Boot permet par défaut et charge SQL à partir des emplacements standard schema.sql et data.sql (à la racine du chemin de classe). En outre Spring Boot charger les fichiers schema-${platform}.sql et data-${platform}.sql (si présent), où la plate-forme est la valeur de spring.datasource.platform, par exemple. vous pouvez choisir de définir le nom du fournisseur de la base de données (hsqldb, h2, oracle, mysql, postgresql, etc.).

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

Questions connexes