java jdbc junit hsqldb dbunit

java - ¿Cómo hago pruebas con DBUnit con JDBC y HSQLDB sin tener que enfrentar una excepción NoSuchTableException?



junit (3)

Estoy tratando de usar DBUnit con JDBC y HSQLDB sin formato, y no logro que funcione, aunque he usado DBUnit con Hibernate anteriormente con gran éxito. Aquí está el código:

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 este es el 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 elimino la línea databaseTester.onSetup (), obtengo 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 él como debería:

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

¿Que me estoy perdiendo aqui?

EDITAR : Como @mlk señala, DBUnit no crea tablas. Si inserto lo siguiente antes de agregar 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();

Publiqué una pregunta de seguimiento como ¿Hay alguna forma para que DBUnit cree automáticamente tablas desde un conjunto de datos o dtd?


En caso de que cree sus tablas por adelantado como se sugiere aquí y aún así obtenga una excepción NoSuchTableException, entonces hay algo mal con el esquema. Antes de volverse loco, jugueteando con él en todo tipo de formas extrañas y maravillosas, intente establecer el parámetro de esquema en PÚBLICO cuando cree la IDatabaseConnection , así:

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

Me tomó algunos pasos a través del código DbUnit con el depurador pero esto parece hacer el truco.


dbUnit no crea tablas. Tampoco podría con la información limitada dada 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 conseguí que el DBA le diera a cada desarrollador su propia base de datos. Luego, cada desarrollador 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 deben mantener sus bases de datos actualizadas), pero significa que no es necesario desordenar la creación de la base de datos para cada ejecución y puede estar seguro de que las consultas se ejecutaron en el trabajo de prueba en vivo.

La segunda razón fue la velocidad. Descubrí que crear la base de datos en memoria demoraba más que simplemente conectarse a una base de datos existente.

La tercera razón fue que la demolición no es destructiva (el inicio borra la base de datos). Esto significa que puedo ejecutar el SQL bajo prueba en la base de datos para ayudar a averiguar por qué falla una prueba.

Actualización : 20171115

Desde entonces he cambiado a usar las reglas de JUnit que inician una instancia real del servidor de la base de datos y algo como FlywayDB para construir la base de datos (y usar los mismos scripts en vivo que en la prueba, con la aplicación responsable de construir la base de datos). Es significativamente más lento que usar una base de datos precompilada. Sin embargo, al utilizar microservicios bien definidos (y así reducir la funcionalidad que requiere pruebas) y al ser muy estrictos en qué pruebas se obtiene una base de datos, puede migrar dichos problemas y obtener los beneficios de una base de datos local que siempre coincide.

Desgraciadamente, significa que la prueba de derribo siempre es destructiva, pero un punto de ruptura bien ubicado lo resuelve.


... varios años después ahora tenemos mejores opciones.

Spring Boot / Spring JDBC puede inicializar una base de datos con JDBC simple.

Spring JDBC tiene una característica de inicialización de DataSource. Spring Boot lo 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 cargará el schema-${platform}.sql y data-${platform}.sql (si está presente), donde plataforma es el valor de spring.datasource.platform , por ejemplo, puede elegir establecerlo 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