¿Las pruebas unitarias HSQLDB son un anti patrón?


9

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"?


3
¿No se aplica esta burla a la capa de la base de datos? No diría que fue un antipatrón, siempre y cuando sea una forma simple y apropiada de hacer que esos módulos que dependen de él sean probados en la unidad.
Kilian Foth

2
@KilianFoth sí, pero ¿sigue siendo burlón cuando el "simulacro" (el db) realmente toma un papel activo en el proceso de prueba? Por ejemplo, cuando tiene una clase con alguna dependencia (obligatoria para la creación de instancias de la clase), si desea probar esa clase de unidad, se burla de esa dependencia, pero luego simplemente prueba los métodos de la clase, no preocuparse más por la dependencia burlada, no tiene un papel tan importante en todas las pruebas unitarias de la clase, como HSQLDB tiene en este tipo de pruebas unitarias ...
Shivan Dragon


1
@gnat bueno, personalmente veo esa otra pregunta más como "cómo unir las cosas de prueba en la capa de acceso a datos anterior - deberíamos burlarnos de la capa de acceso a datos o qué", mientras que la mía es "cómo sufro la prueba de unidad en la capa de acceso a datos en sí, ¿es HSQLD y similares una forma válida de burlarse de las cosas? "...
Shivan Dragon

Respuestas:


8

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á.


5

OMI:

  • Si una prueba requiere DB, no es la prueba unitaria. Es prueba de integración o aceptación.
  • Para evitar la necesidad de usar DB en una prueba, debo seguir el principio de inversión del control mediante el uso de inyección de dependencia (o localizador de servicio).
  • Si necesito probar algo con DB, debería crear una VM con base de datos real (con datos falsos o reales, dependiendo de la tarea). Vagrant y Docker son excelentes herramientas para el trabajo.
  • Burlarse del DB es una mala práctica. Es lo mismo que hacerlo mal (burlándose de la base de datos) y luego rehacerlo correctamente (haciendo que funcione con una base de datos real).
  • Está bien para proyectos de prueba de concepto, pero aún así es seguido por rehacer (si se prueba el concepto).
  • Está perfectamente bien usar HSQLDB (o lo que sea) por sí solo si es una herramienta adecuada para el trabajo.

4

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.


Esa es una gran cantidad de instancias de Oracle que sugiere instalar en algunos entornos, nada barato. No olvides el servidor de compilación tampoco.

@ Michael Lo sé, pero ¿cuál es la alternativa?
Uooo

2
Se podría usar HSQLDB trabajando con un dialecto oráculo (ver sql.syntax_oraen 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.

@MichaelT Oracle es gratuito para desarrollo / pruebas. Por lo tanto, no hay costo para instalar otra instancia de Oracle para realizar pruebas. Por supuesto, existe el costo de instalar más hardware para ejecutar todas esas instancias.
Jwenting

2
No lo consideraría una prueba unitaria si estuviera accediendo a un DB no incrustado
herman

4

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.


3

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.


0

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').

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.