DBUnit y aplicaciones JDBC

1
10999

DBUnit y aplicaciones JDBC

1. Introducción

Siempre hemos hecho hincapié en la importancia de los test en el desarrollo de aplicaciones. DBUnit, como se vio en el tutorial «DBUnit – Exportar e Importar BBDD«, es un framework que nos ayuda a testear aquellas clases que interaccionan con las base de datos. Lo habitual hoy en día es utilizar frameworks ORM como Hibernare que nos abstraigan de esta tarea monótona de una manera fácil y no intrusiva en nuestro código, pero todavía existen aplicaciones que no utilizan estos tipos de framework por alguna razón y lo hacen de forma tradicional a través de JDBC.

Si queremos utilizar DBUnit en estos casos tendremos que hacer algunas tareas adicionales para que nuestros test funcionen. Creo que es importante indicar que DBUnit únicamente se encarga de realizar la carga de los datos de prueba antes de ejecutar nuestros test. Por tanto, la creación del modelo de datos no es responsabilidad de DBUnit. Frameworks como Hibernate realizan esta tarea por ti, es decir, se le puede indicar a Hibernate que cree nuestro schema a partir de las entidades definidas en nuestra aplicación. En los casos en los que se usa JDBC, esto será responsabilidad del programador, de lo contrario nos encontraremos con la famosa excepcion «org.dbunit.dataset.NoSuchTableException».

En este tutorial vamos a indicar una forma fácil de solventar el problema de la creación del schema antes de que DBUnit se ejecute.

2. Entorno

Entorno utilizado para escribir este tutorial:

  • Hardware: Mac Book Pro (Core 2 Duo 2,8 Ghz, 4 GB RAM, 500 GB)
  • Sistema Operativo: Snow Leopard
  • Maven:: 2.2.1
  • Spring:: 3.0.1.RELEASE
  • Junit:: 4,5
  • DBUnit:: 2.4.2
  • HsqlDB:: 1.8.0.7

3. DBUnit y JDBC.

3.1 USerService

Imaginemos que queremos testear nuestra clase UserService. Como veis tenemos un método que retorna todos los usuarios de la tabla users.

package com.adictos.tutorial.dbunit;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

@Service
public class UserService {

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	public List getUsers () {
		
		return jdbcTemplate.query("select * from users", new UserMapper ());
	}
	
	private class UserMapper implements RowMapper {

		@Override
		public User mapRow(ResultSet rs, int rowNum) throws SQLException {
			
			return new User(rs.getInt("id"), rs.getString("name"));
		}
		
	}
}

3.2 UserServiceTest

Ahora creamos nuestro Test.

package com.adictos.tutorial.dbunit;

import java.util.List;

import junit.framework.Assert;

import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.adictos.test.DBUnitUtils;

@RunWith (SpringJUnit4ClassRunner.class)
//Indicamos el fichero de configuración de spring
@ContextConfiguration (locations = {"classpath:context-test.xml"})
public class UserServiceTest {

	public static final String DRIVER_NAME_HSQLDB = "org.hsqldb.jdbcDriver";
	public static final String URL_HSQLDB = "jdbc:hsqldb:mem:dbunit";
	public static final String USER_HSQLDB = "sa";
	public static final String PASSWORD_HSQLDB = "";

	@Autowired
	UserService userService;	
	
	
	@BeforeClass
	public static void startUp ()  {
		try {
			//Creamos las tablas necesarias para el test antes de cargar los datos
			DBUnitUtils.executeSql(DRIVER_NAME_HSQLDB, 
					URL_HSQLDB, USER_HSQLDB, 
					PASSWORD_HSQLDB, "ddl");
			//Cargamos los datos para el test
			DBUnitUtils.createData(DRIVER_NAME_HSQLDB, 
					URL_HSQLDB, USER_HSQLDB, 
					PASSWORD_HSQLDB, "initdb");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	  
	}
					
	@Test
	public void getAllTutorialsNoMigratedOfUserMigrated() {
		
		List users = userService.getUsers();
		Assert.assertNotNull(users);
		Assert.assertTrue(users.size() == 2);
	}

}

Como podéis ver en la línea 34, antes de cargar los datos con DBUnit lanzamos un script DDL con la creación de las tablas. Esto hará que DBUnit no nos lance la famosa excepción «org.dbunit.dataset.NoSuchTableException» cuando en la línea 38 carguemos los datos. Tanto para la creación como la carga hemos implementado una clase de utilidad llamada DBUnitUtils.

package com.autentia.adictos.test;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;

import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.stream.IDataSetProducer;
import org.dbunit.dataset.stream.StreamingDataSet;
import org.dbunit.dataset.xml.FlatXmlProducer;
import org.dbunit.ext.hsqldb.HsqldbDataTypeFactory;
import org.dbunit.operation.DatabaseOperation;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.test.jdbc.SimpleJdbcTestUtils;
import org.xml.sax.InputSource;

/**
 * Clase para trabajar
 * como la librería de DBUnit
 * 
 *
 */
public class DBUnitUtils {
	
	/**
	 * Rellena la base de datos con la información almacenada de un fichero XML.
	 */
	public static void createData(String driverName, String urlDB, String userDB, String passworDB, String nameXML) throws Exception  {

		Connection conn = null;
		// Connect to the database
		DriverManager.registerDriver((Driver)Class.forName(driverName).newInstance());
		conn = DriverManager.getConnection(urlDB, userDB, passworDB);
		IDatabaseConnection connection = new DatabaseConnection(conn);

		// Configuramos DBUnit para usar un large dataset
		DatabaseConfig config = connection.getConfig();
		config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new HsqldbDataTypeFactory());
		
		//Recuperamos el fichero con los datos a cargar
		InputStream is = DBUnitUtils.class.getClassLoader().getResourceAsStream(nameXML + ".xml");
		
			
		IDataSetProducer producer = new FlatXmlProducer(new InputSource(DBUnitUtils.class.getClassLoader().getResourceAsStream(nameXML + ".xml")));

		IDataSet dataSet = new StreamingDataSet(producer);

		//Insertamos los datos
		DatabaseOperation.INSERT.execute(connection, dataSet);

		conn.close();
	}
	
	/**
	 * Ejecuta un script en la base de datos.
	 */
	public static void executeSql(String driverName, String urlDB, String userDB, String passwordDB, String nameSql) {
		//Ejecutamos el ddl utilizanod la clase de utilidad que nos ofrece spring
		SimpleJdbcTestUtils.executeSqlScript(new SimpleJdbcTemplate(new DriverManagerDataSource(driverName,urlDB,userDB,passwordDB)), new ClassPathResource(nameSql+".sql"), false);		

	}

}

Como veis, en la línea 65 utilizamos la clase SimpleJdbcTestUtils con el fin de lanzar el fichero ddl para la creación de las tablas.

3.3 Ficheros ddl.sql y initdb.xml

Ahora creamos los ficheros ddl.sql y initdb.xml necesarios para la creación y carga respectivamente.

DROP TABLE users if exists;

CREATE TABLE users (
  id integer NOT NULL IDENTITY,
  name varchar(255) NOT NULL,  
  PRIMARY KEY (id)
);


  
  

3.4 context-test.xml

Como habéis podido comprobar estamos utilizando Spring. En nuestro test hemos indicado que nuestro fichero de configuración de Spring se encuentra en el classpath con el nombre context-text.xml. En él hemos configurado el dataSource y el JdbTemplate que utilizará nuestra clase UserService e igualmente, en la línea 15 se le indica a Spring que escanee a partir del paquete «com.adictos» para que añada automáticamente a la configuración de spring todas las clases anotadas con @Service,@Component, etc.. sin la necesidad de crearlos en el fichero xml con la etiqueta .




	
  	
        
        
        
    	
	
	
		
	
						

Ahora cuando ejecutemos nuestro test con maven «maven test» veremos que funciona correctamente. Para aquellos quienes os interese, os dejo el proyecto completo aquí.

4. Conclusión

Desde Autentia siempre recomendamos la utilización de test en nuestras aplicaciones independientemente de la naturaleza de nuestro proyecto. Con este tutorial hemos visto como testear con DBUnit clases que acceden a la base de datos a través de JDBC.

1 COMENTARIO

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad