2009-10-07 13 views
16

Estoy tratando de usar DBUnit con JDBC y HSQLDB, y no puedo hacer que funcione, aunque he usado DBUnit con Hibernate anteriormente con gran éxito. Aquí está el código:¿Cómo pruebo con DBUnit con JDBC y HSQLDB sin enfrentar una excepción 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"); 
    } 
} 

Y esta es la dataset.xml en cuestión:

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

Esta prueba me da una 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 quito el databaseTester.onSetup () línea, me sale una SQLException en su lugar:

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) 

El conjunto de datos en sí mismo está funcionando, ya que puedo acceder a ella como debería:

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

Qué me estoy perdiendo aquí?

EDIT: Como @mlk señala, DBUnit no crea tablas. Si inserto lo siguiente antes de añadir el conjunto de datos, todo va 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(); 

He publicado una pregunta de seguimiento como Is there any way for DBUnit to automatically create tables from a dataset or dtd?

Respuesta

19

DBUnit no crea tablas. Tampoco podría hacerlo con la información limitada proporcionada en el archivo XML. Hibernate creo que puede crear las tablas.

Esta es una de las razones por las que dejé de usar bases de datos en memoria y, en su lugar, obtuve el DBA para dar a cada desarrollador su propia base de datos. Cada desarrollador luego mantiene la base de datos actualizada utilizando los mismos scripts que luego se ejecutan en vivo. Esto agrega una pequeña sobrecarga (todos los desarrolladores necesitan mantener sus bases de datos al día) pero significa que no necesita preocuparse por crear la base de datos para cada ejecución y puede estar seguro de que las consultas se ejecutaron en prueba en vivo.

La segunda razón fue la velocidad. Descubrí que la creación de la base de datos en memoria tomó mucho más tiempo que la simple conexión a una base de datos existente.

La tercera razón fue que el derribo no es destructivo (el inicio borra la base de datos). Esto significa que puedo ejecutar el SQL bajo prueba en la base de datos para ayudar a determinar por qué una prueba está fallando.


actualización: 20171115

Desde entonces, he pasado a utilizar JUnit rules that start up a real instance of the database server y algo así como FlywayDB para construir la base de datos (y usando los mismos scripts en vivo como en la prueba, con la aplicación responsable de la construcción la base de datos). Es significativamente más lento que usar una base de datos preconstruida. Sin embargo, al usar microservicios bien definidos (y por lo tanto, reducir la funcionalidad que necesita pruebas) y al ser muy estricto con las pruebas que obtienen una base de datos, puede migrar dichos problemas y obtener los beneficios de una base de datos local que siempre coincide con la realidad.

Por desgracia, significa que la destrucción de la prueba siempre es destructiva, pero un punto de quiebre bien ubicado lo resuelve.

+0

ahora han cambiado a una instancia local de Oracle XE se ejecuta en una máquina virtual. La razón de esto es que podemos seguir desarrollando cuando no está conectado a la red interna. –

+3

Con una base de datos en memoria, puedo ejecutar pruebas de unidades en cualquier lugar, sin tener que cambiar ninguna configuración y sin tener que iniciar un servidor de bases de datos. Principalmente se ejecutan en varios cuadros de desarrollo y en el servidor de CI. Esa es una gran ventaja en mi libro. – Spencer

+0

Sí lo es. Personalmente encontré que es significativamente más lento, sin embargo, esto puede haber cambiado ahora. El tiempo necesario para iniciar una instancia de Oracle XE de VM'ed local es algo breve una vez al día. –

0

En caso de que cree sus tablas por adelantado como sugiere here y aún obtenga una NoSuchTableException, entonces hay algún problema con el esquema. Antes Ahora gire loco, jugando con él en todo tipo de formas extrañas y maravillosas, intente establecer el parámetro de esquema para PÚBLICA cuando se crea la IDatabaseConnection, así:

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

Me tomó un poco de caminar a través de la Código de DbUnit con el depurador, pero esto parece ser el truco.

4

... varios años más tarde, ahora tenemos mejores opciones

primavera de arranque/Primavera JDBC puede inicializar una base de datos con JDBC normal.

Spring JDBC tiene una función de inicialización de DataSource. Spring Boot habilita de forma predeterminada y carga SQL desde las ubicaciones estándar schema.sql y data.sql (en la raíz de la ruta de clase). Además, Spring Boot va a cargar los archivos schema-${platform}.sql y data-${platform}.sql (si está presente), donde la plataforma es el valor de spring.datasource.platform, p. puede elegir establecerlo en el nombre del proveedor de la base de datos (hsqldb, h2, oracle, mysql, postgresql, etc.).

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

Cuestiones relacionadas