Estoy realmente confundido cuando veo mucha implementación de base de datos en memoria utilizada para las pruebas, porque también escuché mucho de las mejores prácticas de pruebas de integración que el entorno que ejecuta la prueba debe parecerse lo más posible al entorno de producción, incluido el sistema operativo , biblioteca, motor de base de datos, etc.
¿Que me estoy perdiendo aqui?
Respuestas:
En una situación típica de desarrollo de software, las pruebas se utilizan en dos puntos: durante el desarrollo y antes de mover el producto a lo largo de la cadena de desarrollo.
La primera situación, ejecutar pruebas durante el desarrollo, cumple objetivos a corto plazo: definir tareas (como en TDD: escribir una prueba fallida, luego hacerla pasar), evitar regresiones, asegurarse de que sus cambios no rompan nada más, etc. las pruebas deben ser extremadamente rápidas: idealmente, todo su conjunto de pruebas se ejecuta en menos de 5 segundos, y puede ejecutarlo en un bucle junto a su IDE o editor de texto mientras codifica. Cualquier regresión que introduzca aparecerá en cuestión de segundos. Las pruebas rápidas son más importantes en esta fase que detectar el 100% de las regresiones y errores, y dado que no es práctico (o absolutamente imposible) desarrollar copias exactas de los sistemas de producción, el esfuerzo requerido para lograr pruebas perfectas aquí no vale la pena. eso. El uso de bases de datos en memoria es una compensación: no son copias exactas del sistema de producción, pero ayudan a mantener las pruebas por debajo del límite de 5 segundos; si la elección es entre una configuración de base de datos ligeramente diferente para mis pruebas relacionadas con la base de datos, y ninguna prueba en absoluto, sé lo que elijo.
La segunda situación, mover el código a lo largo de la cadena de desarrollo, sin embargo, hace requerir pruebas exhaustivas. Dado que podemos (y deberíamos) automatizar esta parte del proceso de desarrollo, podemos permitirnos pruebas mucho más lentas, incluso si una prueba completa lleva horas, programar una compilación nocturna significa que siempre tenemos una imagen precisa de la base de código de ayer. Ahora es importante simular el entorno de producción con la mayor precisión posible, pero nos lo podemos permitir. Por lo tanto, no hacemos la compensación en la base de datos en memoria: instalamos la misma versión exacta del mismo DBMS que los sistemas de producción y, si es posible, la llenamos con datos de producción reales antes de que comience la prueba.
fuente
Supongo que es una velocidad de compensación / coincidencia con el medio ambiente. Las pruebas deben ejecutarse con frecuencia, y eso significa que deben ser rápidas. Especialmente pruebas unitarias, que no deberían tomar más de unos segundos.
Las pruebas de integración se ejecutarán más lentamente, pero cuando son rápidas, puede ejecutarlas con más frecuencia. Por ejemplo, antes de cada commit. Por supuesto, no es tan completo como un entorno completo, pero al menos está probando la capa de mapeo, el SQL generado, cómo las partes se comunican entre sí, etc. En el caso de una base de datos costosa, también se asegura de no hacerlo ' No es necesario comprar una licencia para todos. Puede detectar más errores cubriendo el 90% del código con pruebas ejecutadas una vez por hora que cubriendo el 100% de las pruebas de código una vez por día o peor, semana.
Dicho esto, por supuesto, necesitas probar con la base de datos real y un entorno totalmente integrado. Es posible que no ejecute esas pruebas con tanta frecuencia, pero dado que su prueba anterior ya le dio confianza, todo lo que queda es un extraño error específico de la plataforma.
fuente
Para realizar pruebas simples, burlarse de la capa de acceso a la base de datos es perfectamente aceptable. Usted llama
getName()
, llama al DAO que se ha burlado y devuelve "John" para el primer nombre y "Smith" para el apellido, los ensambla y todo es perfecto. No es necesario probar la unidad de una base de datos allíLas cosas se vuelven un poco más cuando la lógica se vuelve un poco más compleja. ¿Qué pasaría si tuviera un método "createOrUpdateUser (...)"? Si se burló de la base de datos, puede verificar que un método dado se haya llamado una vez con un determinado parámetro cuando el simulacro no devuelve objetos y se invoca un método diferente en la base de datos cuando devuelve un objeto existente. Esto comienza a llegar a esa línea difusa donde podría ser más fácil (especialmente si ya estaba allí) girar una base de datos especializada en memoria y probar ese código con datos preconfigurados.
En algún código real en el que trabajé (punto de venta), teníamos un
resumeSuspededTransaction(...)
método. Esto llevaría la transacción de la base de datos a un objeto (y sus componentes) y actualizaría la base de datos. Nos burlamos y un error acechaba en el código en algún lugar con la serialización y deserialización de los datos que van a la base de datos (cambiamos un tipo que se serializó de manera diferente en la base de datos).El simulacro no nos mostró el error porque estaba devolviendo su camino feliz: serializar la transacción, almacenarla en el simulacro, deserializarla del simulacro, probar que son iguales. Sin embargo, cuando serializa un objeto con un cero inicial en la base de datos, los descarta y luego lo recombina de nuevo en una cadena sin los ceros. Detectamos el error sin la base de datos a través de la resolución de problemas (no fue tan difícil de detectar una vez que supimos que estaba allí).
Más tarde, pusimos una base de datos allí y nos dimos cuenta de que el error nunca habría superado esa prueba junit si hubiéramos ido a una base de datos en memoria.
En memoria las bases de datos tienen las ventajas:
fuente
Esto depende mucho del sistema de base de datos que esté utilizando. Cuando su sistema de base de datos le proporciona una alternativa en memoria que es casi 100% API y comportamiento compatible con una configuración de base de datos basada en disco (a excepción de la velocidad y la seguridad a prueba de fallas, por supuesto), entonces usar la variante en memoria obviamente está bien .
Sin embargo, si su sistema de base de datos tiene diferencias significativas entre la configuración en memoria y el uso sin memoria, tiene razón: en este caso, las pruebas de integración tienen un mayor riesgo de sombrear un error. Pero incluso entonces, es posible que pueda "abstraer esas diferencias" por sí mismo, dado que conoce bien su sistema de base de datos y las diferencias.
fuente
En palabras simples:
La burla de partes importantes de la arquitectura está bien (y es imprescindible) para las pruebas unitarias .
Pero para las pruebas de integración, estoy totalmente de acuerdo con usted. La burla no debe hacerse y debe proporcionarse un entorno lo más similar posible al real.
Después de todo, las pruebas de integración consisten en probar cómo se comportan juntas las diferentes partes de la arquitectura.
fuente