viernes, 30 de octubre de 2009

Pruebas de base de datos con DbUnit

Cuando se desarrollan aplicaciones que acceden a una base de datos, es conveniente verificar que los datos se están manipulando de forma correcta. Para ello, es necesario hacer pruebas sobre el código que realiza esta manipulaciones de datos.

JUnit es un framework que nos ayuda a la hora de hacer pruebas en nuestra aplicación. Además, también podemos usar DbUnit, que es una extensión de JUnit que permite llevar la base de datos a un estado definido antes de cada prueba y que proporciona clases que nos ayudan a realizar pruebas sobre el contenido de una base de datos.

DbUnit permite importar y exportar el contenido de la base de datos a ficheros xml. Por ejemplo, la tabla PROFESORES se define de la siguiente forma:

Un registro en la tabla PROFESORES, se expresaría en xml como:
<profesores PROFESOR_ID="3" NOMBRE="nombre_profesor"/>

Se puede apreciar que el nombre del elemento es el nombre de la tabla y los distintos atributos son los campos de la tabla y su valor para este registro.

Mediante registros de este tipo se pueden generar distintos conjuntos de datos (datasets) en ficheros xml, que pueden servir como semillas para probar el código que accede a la base de datos en situaciones adecuadas para cada prueba.

Vamos a ver como exportar un esquema completo de la base de datos utilizando DbUnit. En primer lugar, se debe obtener una conexión a la base de datos. Se puede hacer de la siguiente forma:
Class.forName("com.mysql.jdbc.Driver");
Connection jdbcConnection =
DriverManager.getConnection(
"jdbc:mysql://localhost/bdprueba",
"user",
"pwd");
IDatabaseConnection connection =
new DatabaseConnection(jdbcConnection);

Posteriormente pasamos a exportar los datos que hay actualmente en la base de datos. Al exportar hay que tener en cuenta el orden de las tablas ya que se podría romper la integridad referencial que existe entre ellas. Para ello se crea un dataset al que se añaden las tablas de forma ordenada, que se pueden obtener a partir de un DatabaseSequenceFilter:
DatabaseSequenceFilter filter = 
new DatabaseSequenceFilter(connection);
IDataSet datasetAll =
new FilteredDataSet(
filter,
connection.createDataSet());
QueryDataSet partialDataSet =
new QueryDataSet(connection);

String[] listTableNames =
filter.getTableNames(datasetAll);
for (int i = 0; i < listTableNames.length; i++) {
final String tableName = listTableNames[i];
partialDataSet.addTable(tableName);
}

Ahora se exportaría este dataset a un archivo xml:
FlatXmlDataSet.write(partialDataSet,
new FileOutputStream("dataset.xml"));

<?xml version='1.0' encoding='UTF-8'?<
<dataset>
<academias/>
<estilos ESTILO_ID="1" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="3" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="4" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="6" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="8" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="9" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="10" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="12" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<clases/>
<academia_clase/>
<profesores PROFESOR_ID="3" NOMBRE="nombre_profesor"/>
<profesores PROFESOR_ID="6" NOMBRE="nombre_profesor"/>
<profesores PROFESOR_ID="9" NOMBRE="nombre_profesor"/>
<profesores PROFESOR_ID="12" NOMBRE="nombre_profesor"/>
<clase_profesor/>
<profesor_estilo PROFESOR_ID="3" ESTILO_ID="3"/>
<profesor_estilo PROFESOR_ID="6" ESTILO_ID="6"/>
<profesor_estilo PROFESOR_ID="9" ESTILO_ID="9"/>
<profesor_estilo PROFESOR_ID="12" ESTILO_ID="12"/>
</dataset>

Tras esto se ha obtenido un dataset que puede ser usado como semilla para una prueba.

A la hora de hacer pruebas, DbUnit proporciona la clase DatabaseTestCase, que sirve como clase base para las pruebas. Esta clase tiene algunos métodos que debemos sobreescribir. El método getConnection() proporciona la conexión a la base de datos, de forma similar a como hemos visto antes:
protected IDatabaseConnection getConnection() 
throws Exception {

Class driverClass =
Class.forName("org.gjt.mm.mysql.Driver");

Connection jdbcConnection =
DriverManager.getConnection(
"jdbc:mysql://localhost/bdprueba",
"user",
"pwd");

return new DatabaseConnection(jdbcConnection);
}

El método getDataSet() proporciona un dataset que sería la semilla para la prueba que vamos a ejecutar:

protected IDataSet getDataSet() throws Exception {
return new FlatXmlDataSet(
new FileInputStream("dataset.xml "));
}

Los métodos getSetUpOperation() y getTearDownOperation() indican lo que debe hacer cada método antes y después de cada prueba. Antes de cada prueba vamos a limpiar la base de datos y a volver a dejarla en el estado que proporciona el dataset que hemos exportado anteriormente, y después de cada prueba no haremos nada:
protected DatabaseOperation getSetUpOperation() 
throws Exception {
return DatabaseOperation.CLEAN_INSERT;
}

protected DatabaseOperation getTearDownOperation()
throws Exception {
return DatabaseOperation.NONE;
}

Tras esto, podemos escribir nuestros casos de prueba en la clase que extiende de DatabaseTestCase, sabiendo que las pruebas partirán de un estado definido.

Referencias:
http://dbunit.sourceforge.net/index.html
http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=DBUnitEI
http://onjava.com/pub/a/onjava/2004/01/21/dbunit.html
http://www.oreillynet.com/onjava/blog/2005/10/dbunit_made_easy.html

1 comentario: