HSQLDB es genial. (También) tiene un modo incrustado (no se necesita un servidor dedicado), lo que permite la creación rápida de prototipos de cosas como Prueba de conceptos, y también puede ser excelente en aplicaciones listas para producción, como un almacenamiento rápido y simple de varios datos.
Sin embargo, al menos el 90% de los proyectos en los que he trabajado en los últimos años, si tratan de alguna manera con una base de datos SQL, inevitablemente tendrán pruebas unitarias que usan un HSQLDB incorporado.
Efectivamente, estos proyectos (que utilizan la estructura estándar de Maven la mayoría de las veces), tienen un montón de "pruebas unitarias" (o, al menos, algún tipo de pruebas, pero que se encuentran en el área de "pruebas unitarias" del proyecto (como "src / test / java")) que usa una o más instancias incrustadas de HSQLDB para realizar algunas operaciones CRUD y verificar los resultados.
Mi pregunta es: ¿es esto un antipatrón? ¿El hecho de que HSQLDB es fácil de integrar y el servidor incorporado es muy liviano hace que pueda pasarse por alto como "maqueta" de una base de datos real, cuando no debería ser el caso? ¿No deberían tratarse tales pruebas más como pruebas de integración (dado que cada una de ellas está compuesta de "algo" Y la integración de ese "algo" con un servidor de base de datos)? ¿O me falta algo en la definición de "prueba unitaria", y de hecho podemos decir que el uso de HSQLDB como este simplemente se adhiere a la parte "simulacro de dependencias y prueba solo la unidad" de la definición "prueba unitaria"?
fuente
Respuestas:
Considero usar algo como HSQLDB (o DBUnit) al probar mis DAO como un paso necesario para garantizar la calidad sobre el código que escribo al tocar una capa de datos. Como ya se señaló, no es una solución a prueba de balas, pero en combinación con sus dialectos puede cubrir una parte razonable de sus casos.
Mi único punto sería: tengamos cuidado cuando hablamos de pruebas de unidad . Cuando pruebo una clase que interactúa con un componente externo que está fuera de mi control (es decir, puede producir un comportamiento no determinista), lo considero automáticamente como una prueba de integración.
Suponiendo que haya factorizado la lógica en la que interactúa directamente con su almacén de datos (a través de controladores JDBC, ORM, etc.) en una clase concreta oculta por una interfaz, se desarrollaría una prueba de unidad adecuada para su DAO pasándola a ella Una implementación simulada concreta de la interfaz que devuelve un conjunto de valores conocidos con los que lo probará.
fuente
OMI:
fuente
Use la misma base de datos para pruebas (unitarias) que está usando en su entorno de producción.
La razón es simple: las bases de datos se comportan de manera diferente. Cada base de datos tiene sus propias funciones propietarias. Incluso si usa una capa ORM para acceder a la base de datos, su base de datos puede comportarse de manera diferente, también en cuanto al rendimiento.
Por supuesto, la ventaja de una base de datos integrada para pruebas unitarias es que no tiene que configurar nada. Pero instalar una base de datos en cada máquina de desarrollador y configurarlo para usarlo en pruebas unitarias no es tan difícil.
Tuve la misma situación en un proyecto hace algún tiempo. Utilizamos JDBC para ejecutar sentencias SQL en la base de datos. Cuando decidimos escribir pruebas para nuestra aplicación, utilizamos una base de datos integrada. Eso condujo a situaciones en las que algunos errores no podían reproducirse con pruebas unitarias, y algunas partes de la aplicación no podían probarse porque la base de datos integrada no admitía las funciones de nuestra base de datos de producción. Por lo tanto, cada desarrollador instaló la misma base de datos que también utilizamos en el entorno de producción en la PC para ejecutar las pruebas, que funcionó mucho mejor.
fuente
sql.syntax_ora
en hsqldb.org/doc/guide/dbproperties-chapt.html ): no es perfecto, pero es lo suficientemente bueno para la mayoría de las cosas. Como observa, no es una solución de todo, pero resuelve los problemas de licencias múltiples necesarias y permite compilaciones independientes que no dependen de otro servicio en ejecución. Otro enfoque sería dbunit . De hecho, hay compensaciones con cada enfoque.Encontré y arreglé algunos problemas realmente malos y aceleré enormemente mi desarrollo probando contra la base de datos HSQL. A menudo, el nivel más bajo de clases de adaptadores (es decir, sus DAO) pueden no probarse en las pruebas unitarias porque puede ser difícil desacoplarlos de un viaje de ida y vuelta real a una base de datos en vivo. Me he burlado de los artefactos de Connection y JDBC en el pasado, pero en realidad fue mucho más difícil que probarlo en una base de datos en memoria.
En un proyecto, desarrollé y probé contra HSQL, ejecuté localmente contra MySql y lo implementé en producción contra SQL-Server. Sorprendentemente, funcionó bien. El mayor problema de integración que encontré se debió a mi propio malentendido de la especificación (segundos frente a milisegundos, jajaja).
Si bien el marco de persistencia puede enmascarar la base de datos subyacente (como lo hace Hibernate), el marco de persistencia en sí mismo puede agregar una semántica lo suficientemente complicada como para que ejercitarlo de forma aislada pueda eliminar muchas peculiaridades antes de llegar a las pruebas de integración completas.
Considere el caso en el que está utilizando Hibernate o JPA para crear un conjunto de resultados complicado con muchas uniones. Si es desagradable y requiere muchos intentos, puede desarrollarlo y probarlo en una base de datos en vivo. Pero también podría desarrollarlo y probarlo en una base de datos en memoria con menos sobrecarga. Tampoco tiene que preocuparse por los scripts de configuración / desmontaje para los accesorios de su base de datos, o por coordinar pruebas y compilaciones con otros. Y si prueba con la base de datos en memoria, disfruta de los beneficios de tener esas pruebas para la regresión, al igual que otras pruebas unitarias.
He escuchado el término "Prueba de componentes" para pruebas que son más que pruebas unitarias, pero que aún se realizan de forma aislada.
Las pruebas unitarias, las pruebas de componentes (si ese es realmente su nombre) y las pruebas de integración proporcionan valor. Los equipos pueden prescindir de uno u otro (sí, muchos equipos no realizan pruebas unitarias y dependen únicamente de las pruebas de integración), pero si lo hace, está perdiendo los beneficios que aportan los otros niveles de pruebas.
En el caso de las pruebas que se aíslan en virtud de la integración en la memoria, el beneficio es la validación rápida del código y luego la regresión rápida: los beneficios de las pruebas aisladas y la necesidad de instalaciones, licencias o hardware adicionales. Le permite validar más niveles de código de forma aislada que si acabara de probar sus DAO hasta que se aprovisionara la base de datos.
Entonces hay un valor práctico. No es obligatorio, pero he sido más feliz que menos cuando lo hice.
fuente
Utilizo enfoques como ese en el pasado, no estoy seguro de si esto es un "antipatrón" (algunas personas intentan elevar sus sentimientos o experiencias personales a reglas universales, no lo estoy), pero prefiero otro enfoque:
Para la prueba unitaria, la prueba unitaria real no utiliza elementos externos como una base de datos en memoria (no es realmente liviana si se compara con un hashMap o un stub que usa alguna biblioteca de stub). Si usa DI y patrones simples como Repository o DAO para su acceso a datos, esto es muy fácil de lograr. Mi objetivo es tener muchas pruebas unitarias que se ejecuten realmente rápido, y con rapidez estoy pensando en una prueba de 3k en menos de un minuto.
Para la prueba de integración, prefiero usar el software de almacenamiento de datos real en esta prueba, el objetivo de esta prueba es demostrar la integración entre mi software y el almacenamiento de datos real, usar un almacenamiento de datos diferente aquí rompe la intención de esto prueba. Intento escribir la prueba de menor integración posible para demostrar esta integración, y generalmente esta prueba se ejecuta fuera de la compilación normal (por ejemplo, solo en compilaciones nocturnas)
A veces uso HSQLDB para crear demostraciones simples o pruebas de conceptos, es una gran herramienta, pero ya no veo cuál es el lugar para esta herramienta en mi flujo de trabajo de desarrollo normal.
fuente
Para los productos de acceso a datos de pruebas unitarias como MyBatis, las pruebas que usan HSQLDB incorporado están perfectamente bien en mi opinión (y sé que al menos en MyBatis están usando HSQLDB exactamente para esto).
Para la mayoría de los otros proyectos, consideraría esta exageración. Haría algunas pruebas de integración simples (estas son pruebas que potencialmente tienen efectos secundarios en otras pruebas) que acceden a la base de datos real, asegurando que cada consulta / declaración se use al menos una vez. Debería haber muchas menos pruebas de integración que las pruebas unitarias en el proyecto.
Para las pruebas unitarias, me burlaría del DAO o lo que sea que acceda al DB (el 'adaptador').
fuente