Publica tu how-to

Dinos como hacer lo que sabes hacer, mándanos un email a wdonet@gmail.com y lo publicamos (dos días máximo) o si te interesa unirte al equipo de redactores, también háznoslo saber por correo.

Mostrando entradas con la etiqueta junit. Mostrar todas las entradas
Mostrando entradas con la etiqueta junit. Mostrar todas las entradas

DBUnit lo hace facil

Dado que he trabajado con JUnit y DBUnit y he encontrado en ellos unas buenas herramientas para probar el codigo de las aplicaciones en java, pues me dí a la tarea de investigar un poquito sobre como obtener datasets desde una BD, y como cargarlos para realizar pruebas específicas.  Fue entonces cuando me encontré con este artículo de Bill Siggelkow y me dí a la tarea de traducir una parte, también he agregado notas mías, pero pueden encontrar el original en enlace al final del post.

Y dice así:
Si desarrollas aplicaciones que acceden a datos relacionales necesitas verificar el código de tu aplicación trabaje con los datos, como fue diseñado.  Cuando usas Hibernate o algún otro framework que implemente JPA, deberías confirmar que tus mapeos dirijan a Hibernate para almacenar y recuperar la información correctamente.  Yo implemento este tipo de pruebas usando JUnit.  Nadie puede refutar que las pruebas contra una base de datos activa es fundamental - no hay una mejor forma para verificar tus mapeos.

Pero para probar contra la base de datos se requiere que los datos se encuentren en un estado inicial.  Puedes cargar la base de datos manualmente antes de correr tu prueba pero eso se vuelve monotono y propenso a errores. DBUnit resuelve este problema.  Este puede precargar la base de datos para cada una de tus pruebas, basado en un grupo de datos dentro de un xml (comúnmente llamado dataset).  El formato de este dataset es sencillo de entender; aquí hay un ejemplo de tres tablas de una base de datos MySQL.  Los nombres de los elementos empatan con los nombres de las tablas y sus atributos con los nombres de sus columnas. Cada elemento implica un registro en esa tabla.

<dataset>
    <cliente id_cliente="778899" id_estatus = "1" id_sucursal="98765"/>
    <banco id_banco="1" nombre="BNMX" descripcion="Banamex" activo="1"
valor="0"/>
    <pago id_cliente = "778899" id_estatus = "1" id_tipo_producto =
"1" id_promotor = "1" id_sucursal = "58" />
</dataset>

Para una base de datos pequeña donde solo necesitas cargar unas pocas tablas con unos pocos registros puedes crear el dataset manualmente. Pero seguramente no querás hacerlo con una base de datos empresarial compleja que contiene cientos de tablas con nombres de columnas complejas.  Es más facil si le permites a DbUnit extraer los datos por ti.

Observaciones sobre Pruebas Unitarias

Analizando las constantes e incansables ocasiones que nuestro líder de proyecto habla sobre la necesidad de hacer pruebas unitarias (automatizadas), y que no siempre estuve de acuerdo, dado el tiempo que se requiere para construirlas y que en la mayoría de las veces, las fechas de entrega negociadas con el cliente nos ahorcan en los tiempos que podemos dedicar a esta práctica, me he dado cuenta de lo siguiente.

Evidentemente sería mucho más útil tener pruebas unitarias que se construyan desde un principio para que en la vida del proyecto se ejecuten periódicamente y nos aseguremos que las partes de dicho proyecto siguen funcionando como deben, independientemente de la integración de nuevos módulos, refactoring de clases, optimización de código e inclusive corrección de estilo.

Pero para lograrlo y evitar el tedio al realizar las pruebas unitarias considero que hay que pensar en lo siguiente:
  1. Para no hacer esfuerzos sin ganancia, es absolutamente necesario planear los puntos críticos a probar unitariamente en los distintos módulos del proyecto.
  2. Así como los Casos de Uso se desarrollan antes que el diseño y los diagramas UML preceden a la construcción de un proyecto, es vital que las pruebas unitarias se armen antes de la construcción.
  3. No es necesario crear una prueba unitaria por cada Dao, Servicio, Pojo, Controller, ViewHelper o Utilería habido o por haber.
  4. Las pruebas que deberían automatizarse son aquellas que tienen una mayor probabilidad de no cambiar (en concepto) a lo largo del proyecto. Cuando sea necesario integrar ajustes nuevos y provoquen un fallo en las pruebas automatizadas ya existentes, se pueden actualizar dichas pruebas con cambios mínimos para mantenerlas como símbolo de que nuestro sigue funcionando con los requerimientos de un principio.
  5. Es necesaria una comunicación plena en el equipo de desarrollo por cuestiones de conflictos de actualizaciones, sobre todo si se esta trabajando en el mismo repositorio y los cambios de uno afectan a las pruebas unitarias de otro.
  6. Para visualizar el correcto funcionamiento de una prueba unitaria y localizar el error si esta falla (sin hacer debug) es realizar un correcto logging, de manera que éste mismo explique claramente la etapa que transcurre (con datos self-explaining) y compruebe el estado del proceso en ejecución.
  7. Es importante contar con un grupo de herramientas adecuadas que nos permitan conectarnos a base de datos y trabajar con datos, simular comportamientos de servicios no-tan-fácilmente-probables, acceder a archivos y verificar su contenido y un grupo de agregados para comprobar los resultados de cada prueba. Quizá funcionen como adaptadores, servicios, factories o daos dedicados exclusivamente para comprobar cosas. Junit tiene un addons que se ve bastante bien.
  8. El que las pruebas unitarias estén correctamente automatizadas y con un adecuado logging (incluyendo los elementos a probar) implica que ya no es necesario hacer debugging para encontrar los errores (algo que solo se puede hacer manualmente).
Una vez planeado así, podríamos ver los resultados que dice el articulo de jamesgolick en su apartado "Breaking Even" : 'si te cuesta 20min. construir una prueba automatizada y 1min. una prueba manual, llegar al punto critico para compararlas es que probases manualmente 20 veces; después de eso, la prueba automatizada se vuelve mucho mas barata y la manual obviamente mas cara, disparándose ambas en sentido contrarios'.

Ustedes que piensan? alguna otra recomendación?