Consejos test para DAO

191 views
Skip to first unread message

yamit c

unread,
Jun 8, 2010, 10:54:28 AM6/8/10
to TDDev
hola

me gustaria tener algunos consejos, para desarrollar las pruebas
unitarias de un Dao, no he tenido inconvenientes con pruebas para
realizar consultas (SELECTs)... sin embargo he tenido muchos problemas
al intentar hacer testing de metodos de actualizacíon o inserción de
datos en mi base de datos a través de un objeto Dao, he pensado
hacerlo usando un rollback() al final del test, en el tearDown, pero
son bastantes las clases Dao que tengo y creo q seo me daria un
problema de rendimiento al momento de ejecutar las pruebas
constantemente, que me recomendarian??

muchas gracias por sus respuestas :)

Iván Párraga García

unread,
Jun 8, 2010, 11:00:58 AM6/8/10
to tdde...@googlegroups.com
La palabra mágica aquí, es DBUnit.

Es un framework que te permite dejar la base de datos en estados conocidos a priori y a posteriori de los tests. El truco es que los tests sean totalmente independientes entre sí, es decir, cada test prepara la base de datos en el estado en  el que supone sobre lo que está testeando; de esta manera todo es mucho más fácil porque no tienes dependencias entre ellos. DBUnit te ayuda MUCHO a gestionar esto de manera automática.

Saludos,

Iván


--
Has recibido este mensaje porque estás suscrito al grupo "TDDev" de Grupos de Google.
Para publicar una entrada en este grupo, envía un correo electrónico a tdde...@googlegroups.com.
Para anular tu suscripción a este grupo, envía un correo electrónico a tddev-sp+u...@googlegroups.com
Para tener acceso a más opciones, visita el grupo en http://groups.google.com/group/tddev-sp?hl=es.


Israel Alcázar

unread,
Jun 8, 2010, 11:50:01 AM6/8/10
to tdde...@googlegroups.com
Coincido plenamente con Iván. Lo mejor es que la base de datos la simules para cada prueba. Nosotros también trabajamos con DBUnit aunque si estas trabajando con Spring v3 ya incluye motores de bases de datos embebidas de forma nativa.

Otra alternativa a la simulación de la base de datos es que hagas transaccional cada Test, es decir, que al finalizar el Test se haga el rollback de la base de datos. Esta opción no te la recomiendo en absoluto ya que va un poco en contra de la filosofía purista de TDD. En spring esto se consigue con la anotación @Transaction.

Saludos,

Domingo Suárez Torres

unread,
Jun 8, 2010, 12:49:32 PM6/8/10
to tdde...@googlegroups.com
Hola Israel,

¿Porque mencionas que hacer rollback despues de cada test va en un poco contra de la filosofia de TDD?

Saludos

2010/6/8 Israel Alcázar <israel...@gmail.com>

Jessica Aguado

unread,
Jun 8, 2010, 1:36:33 PM6/8/10
to tdde...@googlegroups.com
Hola, 
iba a lanzar la misma pregunta que Domingo :D

Nuestras clases de test extienden AbstractTransactionalDataSourceSpringContextTests de este modo el rollback se hace automáticamente al final de cada método de test.

Salu2

2010/6/8 Domingo Suárez Torres <domingo...@gmail.com>

Joaquín Engelmo Moriche

unread,
Jun 8, 2010, 1:43:20 PM6/8/10
to tdde...@googlegroups.com
Buenas,

una cosa, ¿estamos hablando de pruebas unitarias o de integración?

En el primer caso, DBUnit (no conozco si es embebida) u otra cosa como HSQLDB o alternativas embebidas de tal forma que el test no depende de la configuración de un recurso externo y así cumpla los principios FIRST.

En el segundo caso, obviamente al usar recursos externos hay varias opciones. Por ejemplo, si la base de datos es exclusivamente para pruebas, siempre podemos crearla y borrarla después de cada test (lento si, pero es de integración, se permite). El tema de las transacciones con rollback quizás Israel se refiere a que no sigue el patrón de: preparar SUT (sujeto a probar), lanzar operación, asserts ya que no debería preocuparse por limpiar la base de datos. Opción, lanzar un borrado de los datos pero no a través del SUT (Dao en este caso) sino desde JDBC o algo así, como una función "helper" en el mismo test. Esto quizás cuadre más con TDD, no hay que usar el SUT para luego dejar estable la base de datos otra vez.

Un saludo :)
----------------------------------------------------------
Haciendo realidad la agilidad
http://conferencia2010.agile-spain.com/
Madrid 10 - 11 Junio'10
----------------------------------------------------------

Domingo Suárez Torres

unread,
Jun 8, 2010, 1:46:59 PM6/8/10
to tdde...@googlegroups.com
Si usas conexion a la base de datos es pruebas de integración, las unitarias estas aisladas de cualquier dependencia.

DBUnit es un framework no una base de datos como HSQLDB.


2010/6/8 Joaquín Engelmo Moriche <kiniso...@gmail.com>

Jessica Aguado

unread,
Jun 8, 2010, 1:55:14 PM6/8/10
to tdde...@googlegroups.com
Hola, entiendo que estamos hablando de pruebas de integración (dao-bd).

Si se utiliza Spring, la opción de hacer la clase de test extendiendo AbstractTransactionalDataSourceSpringContextTests desliga al objeto de testeo del rollback.

Vendría a ser algo así:

public class DaoTestClass extends AbstractTransactionalDataSourceSpringContextTests{

     @Test
public void testInsercionDeUnObjetoOk(){
  introducirDatosDePrueba();
  insertarObjeto();
  asserts
}
@Test
public void testSelectDeUnObjetoOk(){
  introducirDatosDePrueba();
   seleccionarObjeto()
   asserts
}

@Test
public void testDeleteDeUnObjetoQueNoExiste(){
  introducirDatosDePrueba()
  eliminarObjeto
   asserts
}
...

}

Después de cada método de test se hace un rollback de forma transparente (no se hace el rollback a mano) y así todos los tests son independientes.

DBUnit, me parece interesante para automatizar las pruebas con selenium, en las que si que hay un orden de las cosas que se testean y podemos poner un conjunto de datos de prueba al principio y "limpiarlo" al final del test.

Salu2

Yamit Cardenas

unread,
Jun 8, 2010, 2:35:18 PM6/8/10
to tdde...@googlegroups.com
en realidad estaba hablando de pruebas unitarias, aun q ahora entiendo mejor la diferencia entre las dos, en mi proyecto no uso spring, asi que creo q usare DBUnit

Israel Alcázar

unread,
Jun 8, 2010, 3:44:39 PM6/8/10
to tdde...@googlegroups.com
Hola, estaba dando por supuesto que estábamos hablando de Test Unitarios. Si realmente hacemos un rollback de la base de datos romperíamos el principio de aislamiento de lo que queremos probar (nuestro dao). 

Como bien apuntáis después, si lo que estáis haciendo son test de integración tendría todo el sentido del mundo ya que es la única forma de asegurarnos que el sistema no queda en un estado incosistente después del test.

Por otro lado, aprovecho este hilo para hacer la siguiente reflexión:

¿ Pensáis que hacer Test Unitarios a veces puede resultar una redundancia y una perdida de tiempo? Me explico, en el caso concreto que nos ocupa del diseño de un DAO, pensáis que es necesario tener un Test Unitario que pruebe el DAO para posteriormente tener un test de integración que prueba el DAO contra la base de datos real?

Es mas, si yo posteriormente tengo un test que prueba un servicio que utiliza este DAO, no sería mejor realizar directamente el test de integración del servicio con el DAO y la base de datos real para probar todo en su conjunto?

Me gustaría saber vuestra opinión al respecto.

Muchas gracias.



2010/6/8 Domingo Suárez Torres <domingo...@gmail.com>
Hola Israel,

Jessica Aguado

unread,
Jun 8, 2010, 4:01:57 PM6/8/10
to tdde...@googlegroups.com
Hola,

hasta hace poco te hubiese contestado: hacer test unitarios es una pérdida de tiempo, donde estén los de integración......

La verdad es que mi opinión ha cambiado bastante al respecto y cuantos más test unitarios hago más utilidad les veo. Pero en mi caso, no he hecho nunca un test unitario de un DAO. Cuando testeo un DAO siempre lo hago contra base de datos, y la verdad es que no llego a imaginarme un test unitario de un dao (si algún alma caritativa se anima a ponerme un ejemplo....).

El proceso que sigo es: test de integración del dao, test unitario de service y test de integración del service (aunque no siempre). Antes la parte "test unitario de service" me la saltaba. Me parecía una "pérdida de tiempo" estar haciendo mocks que simulasen el funcionamiento del dao cuando siempre tenía el dao ya implementado. 
Sin embargo, hoy (sin ir más lejos), un compañero y yo estabamos implementando "casi" la misma funcionalidad, pero el estaba con algunos métodos del dao y yo con algunos del service que necesitaban de esa funcionalidad del dao. "Puf"-he pensado-"tengo que esperar a que termine la funcionalidad del dao, así que tendré que tirar por otro lado.... Ah! no! puedo mockearlo!!" y voila! ambos hemos hecho nuestra parte que ha encajado perfectamente. No hemos tenido que esperarnos y la funcionalidad estaba completamente implementada.

Vamos que me estoy volviendo una fanática de los test unitarios :D (al menos de la parte de servicios... ya veremos de los daos, según lo que me conteis).

Salu2

Joaquín Engelmo Moriche

unread,
Jun 8, 2010, 4:10:29 PM6/8/10
to tdde...@googlegroups.com
Buenas Israel,

desde mi punto de vista hay una cosa clara, hay que hacer test unitarios si o si, y también test de integración. El test unitario sería aquel que prueba el dao (siguiendo los principios FIRST como decía antes) con su lógica de persistencia correspondiente. Estas probando tanto su comportamiento como su conexión con un recurso, aunque en este caso se configure embebido. 
Realizar ahora un test de integración igual que el unitario pero cambiando que el recurso sea externo al propio test creo que si es redundante. Y, por esto mismo, considero que no haría falta. El test unitario ya está probando el SUT realmente como se debe.
Coincido contigo que sería más útil hacer el test de integración (o sistema) con el servicio, más el DAO y la conexión real (o embebida, eso creo que es lo de menos, ya estaba probado ;)). 

Un saludo (y nos vemos en dos días) :D

El 8 de junio de 2010 21:44, Israel Alcázar <israel...@gmail.com> escribió:



--

Joaquín Engelmo Moriche

unread,
Jun 8, 2010, 4:14:59 PM6/8/10
to tdde...@googlegroups.com
Hola Jessica,

como alegra saber que la gente cada vez se conciencia más de hacer test unitarios :) Dan información tan rápidamente y tan útil que enganchan ;) Y las situaciones día a día con los compañeros que no lo hagan serán para que se lo piensen, esa es mi experiencia. 

Sobre poner un ejemplo de DAO creo que encontrarás alguno en google con DAO+HSQLDB o en el sitio de DBUnit, etc... no es por ser antipático, es que ahora no puedo colgar uno :) Pero prometo poner código y compartirlo en cuanto tenga un momento por si así sirve de ayuda.

A seguir testeando! :D

Jessica Aguado

unread,
Jun 8, 2010, 4:19:46 PM6/8/10
to tdde...@googlegroups.com
Hola Joaquin,

puede parecer raro... pero esto de testear es un vicio!! jejeje

Con la referencia que me has pasado más que suficiente. Muchas gracias.

José Manuel Beas

unread,
Jun 8, 2010, 5:00:55 PM6/8/10
to tddev-sp
El día que Kent Beck me respondió que él no hacía tests automatizados para todo me quedé de piedra. Pero con el tiempo me he dado cuenta de que el maestro tiene más razón que un santo. A veces, el coste de automatizar un test es muy alto o la certeza que ganas mediante ese test es muy poca. En esos casos, no merece la pena escribir el test.

¿Qué ganamos con un test unitario de un DAO? Pues por ejemplo, poder cambiar de implementación del DAO de uno que maneja los datos en memoria a otro que usa una BD sin más. Mmm, si no puedo hacer eso de manera transparente es porque:
a) mis tests están acoplados a la implementación
b) mi DAO no está suficientemente desacoplado de su contexto
(Ambos casos son dos caras de la misma moneda: necesito abstraer más)

¿Qué ganamos con el test de integración? Buff, creo que aquí depende de cómo sea nuestra arquitectura. Si tenemos un DAO muy acoplado a la estructura de datos (p.ej. usamos JDBC o algo así), entonces adquirimos la certeza de que el SQL y todo eso lo hemos hecho bien. Es laborioso y nos obliga a trabajar mucho los escenarios. Y probablemente nuestros tests estén muy acoplados al código. Pero claro. Es lo que tiene ser un artesano... En cambio, si usamos un ORM (Hibernate, p.ej) o cualquier otro framework para estandarizar el acceso a los datos... sinceramente, hacer unos tests de integración muy exhaustivos me parece excesivo porque se supone que el fabricante del ORM ya ha probado que todo eso funciona. Con escribir unos tests ligeritos que comprueben las principales relaciones yo creo que va que chuta.

Por supuesto, la BD siempre una BD en memoria (en relacionales hsqldb, h2, derby... no es muy importante aunque "dicen" que h2 es la más rápida). En el fondo no creo que hoy día sea relevante la elección, aunque recuerdo que en su momento tuve muchísimos problemas de compatibilidad con el ORM. No tengo experiencia con BBDD NOSQL pero molaría que alguien contara su experiencia.

Eso sí, fiarlo todo a una prueba end-to-end (aun en un entorno aislado) me parece mala idea porque, si la prueba falla, no podemos tener la certeza de qué es lo que falla puesto que hay demasiados puntos posibles de fallo, además de que resulta muy alto el coste de preparar el entorno para poder ejecutar suficientes pruebas y suficientemente independientes.

Un saludo,
Jose Manuel Beas

http://agilismo.es
http://jmbeas.iExpertos.com
http://twitter.com/jmbeas



Pablo Alonso García

unread,
Jun 9, 2010, 3:13:02 AM6/9/10
to TDDev
Hola,

Acabo de toparme con este grupo gracias a un twitt de @kinisoftware...
¡Es genial poder estar en contacto con gente que usa testing en el día
a día!

Precísamente esta semana en mi proyecto estamos implementando tests
para probar DAOs. Yo estoy dándome de cabezazos contra le mesa por no
haber escrito los tests antes que el código (TDD vaya). Lo cierto es
que el proyecto se ha convertido en un pequeño monstruo y es inviable
seguir sin tests que garanticen que no rompamos lo anterior y nos
permitan refactorizar tranquilamente...

La aplicación es un poco especial. Nada que ver con Java y Spring.
Estamos desarrollando una extensión para Firefox con XUL + Javascript
(http://www.libertexto.org/), usando SQLite como SGBD. Aún usando
JavaScript, hemos intentando crear un aplicación multicapa y hemos
implementado un GenericDAO. A la hora de probar nuestros DAOs
simplemente hemos creado una BD de testing. Tenemos una variable
global en la aplicación que determina el entorno en que se ejecuta la
app. De esta forma, al ejecutar los tests, se modifica automáticamente
esta variable para que los DAOs (más concretamente el método del
BaseDAO que determina el fichero que contiene la BD SQLite). Además,
cada vez que se ejecutan los tests se regenera la BD de pruebas. Es
algo similar a lo que hace Rails.

Para las pruebas estamos usando jsUnity (http://jsunity.com/). Es un
"port" de xUnit en Javascript.

Lo que hacemos es que en el SetUp del testsuite insertamos (usando el
propio DAO) una serie de registros de prueba. Cada caso de prueba
instancia el DAO, ejecuta alguna operación (normalmente CRUD) y luego
ejecutamos algunas aserciones (muy similar al ejemplo de Jessica).

El problema en este momento es que la ejecución de las pruebas de un
DAO son casi 2 segundos. Para colmo los tests los estamos ejecutando
desde un fichero XUL, para que se ejecuten en el propio Firefox y
puedan acceder a los componentes XPCOM (en nuestro caso el de acceso a
SQLite). Esto conlleva que cada vez que modificamos código o los
propios tests tenemos que reiniciar el Firefox... :-(

En definitiva un poco berengenal que espero consigamos optimizar de
alguna forma...


Saludos,

Pablo Alonso García
http://alonsogarciapablo.com

David Roncancio

unread,
Jun 9, 2010, 11:16:00 AM6/9/10
to tdde...@googlegroups.com
Hola, hemos estado mirando dbunit para probar los DAOs, sin embargo la aplicación que queremos refactorizar(por que es código legado), tiene una base de datos con muchas tablas y muchos registros(llegando varias tablas a tener mas de 200millones de registros), y como lo que entiendo de dbunit es que se crea un XML con la estructura y datos de la DB, pues no sabemos si estas pruebas van a terminar siendo casi tan costosas como hacer rollbacks, por otro lado no se esta usando spring por lo que la opción que propone Jessica no es tan viable, otro problema que tenemos es que la aplicación es muy orientada a los datos y tiene mucha lógica escrita en Procedimientos Almacenados(SP), por lo que tampoco sabemos cual sea el mejor acercamiento para implementarle las pruebas a estos, y por último no se dispone de un ORM, la idea es que en la refactorización que estamos empezando a hacer se implemente el uso de uno, pero queremos crear Tests para hacer este proceso lo mejor posible.

No se si alguien haya tenido una experiencia similar o sepa como podemos implementar pruebas para una aplicación legada que esta muy orientada a los datos

Cordialmente, 

David Roncancio

2010/6/9 Pablo Alonso García <alonsoga...@gmail.com>
--
Has recibido este mensaje porque estás suscrito al grupo "TDDev" de Grupos de Google.
Para publicar una entrada en este grupo, envía un correo electrónico a tdde...@googlegroups.com.
Para anular tu suscripción a este grupo, envía un correo electrónico a tddev-sp+u...@googlegroups.com
Para tener acceso a más opciones, visita el grupo en http://groups.google.com/group/tddev-sp?hl=es.




--
David Roncancio
(+57) 3014311354

Carlos Ble

unread,
Jun 9, 2010, 2:52:25 PM6/9/10
to tdde...@googlegroups.com
Hola!
Un DAO no debe tener mas logica de negocio que la que trae o lleva datos a un sistema que no es nuestro, es decir, un motor de base de datos. Por tanto no caben tests unitarios sino solo tests de integracion.

En mi experiencia, hacer el test de integracion antes que escribir el codigo, es contraproducente ya que estaríamos asumiendo que el sistema externo tiene un comportamiento que quizás no tiene. Salvo casos contados, nunca escribo los tests de integracion antes que el código. 
De todas formas esto depende mucho de cada caso, teniendo en cuenta que hay muchos tipos de tests de integracion. Desde el que hace un SELECT hasta el que atraviesa la app de punta a punta.

Saludos :-)

José Manuel Beas

unread,
Jun 9, 2010, 3:53:37 PM6/9/10
to tddev-sp
Y aquí es cuando llegamos a hablar de.... ¡¡los mocks!!

Si alguien tiene tiempo y quiere extenderse, por favor que lo haga con gusto, yo sintiéndolo mucho me quedo aquí porque mañana tenemos la Conferencia Agile-Spain 2010 y aún tengo mucho que preparar.


Un saludo,
Jose Manuel Beas

2010/6/9 Carlos Ble <ble.j...@gmail.com>

Carlos Ble

unread,
Jun 9, 2010, 4:33:04 PM6/9/10
to tdde...@googlegroups.com
Los dobles de test solo tienen sentido en tests unitarios y estos serian de integracion :-) Para que los quieres aqui? 
Si estas probando el DAO no necesitamos mock. Yo se que te refieres a que cuando el DAO es un colaborador, pruebas el SUT usando un mock DAO, pero es que la gente al final se confunde con qué es lo que quiere probar :-)

--
Has recibido este mensaje porque estás suscrito al grupo "TDDev" de Grupos de Google.
Para publicar una entrada en este grupo, envía un correo electrónico a tdde...@googlegroups.com.
Para anular tu suscripción a este grupo, envía un correo electrónico a tddev-sp+u...@googlegroups.com
Para tener acceso a más opciones, visita el grupo en http://groups.google.com/group/tddev-sp?hl=es.

Joaquín Robles

unread,
Jun 10, 2010, 12:38:56 PM6/10/10
to tdde...@googlegroups.com
Hola,

La idea de DBUnit es preparar un juego de datos para las pruebas, con unos pocos de registros en cada tabla implicada en el test (normalmente una tabla si el test es unitario).

Entiendo que las pruebas de los DAO's no se deben lanzar sobre una copia de la BBDD de producción de la aplicación que os toca refactorizar (con cientos de millones de registros), sino una BBDD con la misma estructura sin datos, ya se encargará DBUNIT de cargar los registros necesarios para las pruebas.

Si necesitais lanzar pruebas sobre la BBDD que tiene cientos de millones de registros, deberían ser pruebas de integración fuera del flujo de la compilación de cada módulo (mvn clean install, para los compañeros que usen maven), ya que la compilación de un módulo puede alargarse demasiado y convertirse en un infierno.

Si finalmente realizáis pruebas unitarias, es totalmente factible realizar en estas pruebas llamadas a procedimientos almacenados, no hay ningún problema.

Ya para terminar el tostón, si la aplicación tiene mucha lógica en los procedimientos almacenados y estos contienen sql dinámicas es fundamental el uso de test unitarios para los SP, ya que será más facil detectar los problemas causados por cambios en columnas, tablas, ...

Bueno, me he estrenado en el grupo después de un tiempo siendo observador, no se si me he explicado bien ;)

Un saludo a todos, la verdad es que es una alegría participar en un grupo con gente como ustedes.

Carlos Ble

unread,
Jun 10, 2010, 8:20:23 PM6/10/10
to tdde...@googlegroups.com
Un test unitario tiene que ser rapido, y rapido significa decimas de segundo. Un test que ataca a una base de datos no es unitario :-)
Carlos Ble
www.iExpertos.com
www.carlosble.com
Reply all
Reply to author
Forward
0 new messages