¿Estoy probando la unidad o comprobando la integración de mis procedimientos almacenados?

8

Recientemente he tenido muchas ocasiones en las que he necesitado mantener funciones y procedimientos almacenados complejos. Estos ya estaban rotos, por lo general de maneras bastante sutiles: había muy pocas ocasiones en las que llamaba al SP con parámetros válidos y simplemente no funcionaba.

Mi solución fue desarrollar un marco de trabajo que ejecute los procedimientos almacenados dentro de una transacción, después de inicializar la base de datos a las condiciones iniciales que necesitaba, luego probar el resultado esperado, también dentro de la misma transacción. La transacción fue revertida al final de la prueba.

Esto ha funcionado muy bien. Pero algunos llamarían a esto "pruebas de integración", ya que implica la integración con la base de datos. Lo llamo prueba unitaria, ya que probé componentes individuales y casos de prueba individuales para esos componentes, y desde que controlé completamente el estado inicial de la base de datos.

Pero, ¿dónde debe trazarse la línea? ¿Es esta prueba de integración o prueba unitaria? ¿Hay alguna razón práctica por la cual este tipo de prueba es una mala idea? Si esto es "solo" pruebas de integración, ¿alguien tiene sugerencias sobre cómo hacer "pruebas unitarias" reales en estos procedimientos almacenados?


Actualización, 3 años y medio después. En mi proyecto actual, comencé a usar pruebas unitarias SSDT, con éxito, aunque podrían ser mejores. Consulte Verificación del código de la base de datos mediante pruebas unitarias de SQL Server . Por lo general, implementan el proyecto de base de datos en su instancia de SQL Server LocalDB, por lo que esto elimina cualquier duda sobre el entorno de la base de datos que afecta la prueba. Rellene la base de datos con los datos requeridos durante la Prueba preliminar, que elimina las preguntas sobre el contenido de la base de datos. De hecho, utilizo declaraciones MERGE para hacer esto, asegurando que cualquier información que no necesite para la prueba actual se elimine, inserte o actualice de la base de datos antes de la prueba. Tienen problemas:

  • No son rapidos
  • No es posible reutilizar las condiciones de prueba
  • No es posible reutilizar las pruebas previas (a menos que las haga comunes a todas las pruebas en un proyecto)
  • La interfaz de usuario podría mejorarse

Una de las razones de los problemas anteriores es que todavía no me he quejado de ellos. Recomiendo que cualquier persona interesada pruebe esta función y luego se queje. Así se hacen las mejoras.

John Saunders
fuente
1
¿Por qué sería un oxímoron ?
doppelgreener
Buena pregunta. ¿Qué opinas de cambiar el título? Quizás algo como esto: "Cómo probar los procedimientos almacenados de la unidad"
Matthew Rodatus
@Matthew: "editado en colaboración"
John Saunders

Respuestas:

7

El objetivo de las pruebas unitarias no es hacer que un hada de pruebas unitarias mágicas venga y valide su opinión. Es para probar los bloques de construcción más pequeños y simples de su sistema, por lo que no está probando una funcionalidad más extensa y se tropezó porque algo no funcionó de la manera que pensaba. Entonces, ¿ puedes desglosar esto más? No creo que puedas, en cuyo caso:

(a) A mí me suena como una prueba unitaria, y (b) No importa si es una prueba unitaria o no, porque prueba lo que necesita una prueba, ¡lo cual es el punto de usar pruebas unitarias en primer lugar!

Si cree que los procedimientos son demasiado complejos, es posible que desee dividirlos en partes más pequeñas (en los procedimientos de la base de datos o en el código), pero para hacerlo, obviamente, ¡le gustaría tener estas pruebas primero!

Jack V.
fuente
7

La prueba de unidad, por definición, gira en torno a probar una "unidad" de código en su entorno o plataforma en ejecución. La plataforma que usa es una base de datos, por lo que debe usarla, no es integradora.

Una mejor pregunta es por qué te importa. Siempre que esté automatizado y agregue valor, ¿le importa que su prueba en una prueba unitaria, una prueba de aceptación, una prueba de humo o una prueba funcional?

En mi trabajo, actualmente aprovechamos el marco de prueba de la unidad para realizar el Desarrollo impulsado por pruebas de aceptación (ATDD). Algunas pruebas son integradoras, otras no. Casi ninguno de ellos son pruebas unitarias, pero no nos importa siempre que:

  • la prueba agrega valor
  • la prueba no tiene fallas o éxitos falsos (es principalmente determinista)
  • la prueba es automatizada

Actualizar

Todo es una cuestión de costo y beneficio. Cuantas más partes móviles tenga, mayor es el riesgo de tener una prueba no determinista. Las pruebas unitarias clásicas tienen la menor cantidad de partes móviles y, por lo tanto, la menor posibilidad de ser no deterministas. La desventaja es que no está probando los puntos de integración (código, base de datos, fs, red, etc.). Todos estos son útiles para cubrir una prueba, siempre y cuando el riesgo de fallas falsas o éxito sea lo suficientemente bajo.

Las pruebas proporcionan valor en lo que no hacen lo que son. La clave es con qué frecuencia tendrá fallas falsas y éxito. Si tengo fallas falsas durante 2 horas cada mes porque esa es una ventana de mantenimiento para la red, entonces el valor de las pruebas es evidente. Cuando fallan, es obvio que hay algo mal con el recurso en red, no una prueba en particular. Y ahora tiene más cobertura de prueba precisamente porque está probando esos puntos de integración.

dietbuddha
fuente
Una de las razones por las que me importa es que algunos lugares se quejarán si sus pruebas unitarias no son "pruebas unitarias" por su definición. Otra razón es que surgió en los comentarios sobre " ¿Existe un término medio? (Pruebas unitarias versus pruebas de integración) "
John Saunders
@John Según la respuesta de @ dietbuddha y la investigación que he leído: Debido a que está utilizando la pila de red y el servidor de base de datos, sus pruebas no son "en su mayoría deterministas". No deben clasificarse como pruebas unitarias. Pero, por supuesto, esa es solo mi opinión.
Matthew Rodatus
1
@Matthew: No sé en qué plataformas se desarrolla, pero le garantizo que la pila de red y el servidor de base de datos que uso no fallan muy a menudo. De hecho, las fallas de estos componentes pueden ignorarse con el propósito de realizar pruebas.
John Saunders
@John Saunders: respuesta actualizada
dietbuddha
2

Creo que depende de dónde provienen los datos. Si está creando sus condiciones de prueba en el prefijo de prueba, creo que es razonable llamarlo una prueba unitaria. De lo contrario, te interesan los argumentos quisquillosos sobre lo que cuenta como "preexistente" para una prueba unitaria. Así como las pruebas unitarias de su base de datos se basan en la existencia de tablas de la base de datos, etc., las pruebas unitarias fuera de la base de datos se basan en cosas como definiciones de clase y, a menudo, instancias de esos clssses. Eso no está mal, es realista.


fuente
1

Consideraría que se trata de pruebas de integración:

  1. Es mucho más lento de lo que debería ser una prueba unitaria.
  2. No ejerce una sola unidad de código atómica: ejercita su procedimiento, el servidor de la base de datos, la pila de red, etc.
  3. No será fácil detectar dónde ocurrió el error si la prueba falla. Tendrá que ver cada falla manualmente para ver si fue una falla externa del sistema o su código.

Sin embargo, las pruebas como las que usted describe son invaluables. Recientemente comenzamos a agregar pruebas así, para probar procedimientos almacenados que son imposibles de probar manualmente en ciertos entornos. No conozco otra forma de tener pruebas automatizadas para procedimientos almacenados.

Por lo tanto, estas pruebas son una gran idea, pero llámelas pruebas de integración: use una categoría de prueba o sufijo de nombre para distinguirlas de las pruebas unitarias regulares. De esta manera, puede marcar las fallas de las pruebas de integración de manera diferente a las fallas de las pruebas unitarias en su automatización de compilación.

Matthew Rodatus
fuente
@Matthew: no pruebo el servidor de base de datos o la pila de red, como tampoco pruebo .NET BCL o CLR. Además, no he tenido problemas para localizar fallas. Quizás debería dar un ejemplo más detallado del tipo de prueba que quiero decir.
John Saunders
@John Cuando dije "prueba el servidor de la base de datos y la pila de red", quiero decir que estás probando cualquier código que estés ejercitando. El .NET BCL / CLR debe tener un ticket en la prueba de la unidad: ¡no puede escribir código sin ellos! Pero, una prueba que habla con un servidor de base de datos también está ejerciendo (es decir, probando) el servidor y la red. Supongo que debería preguntar: ¿Cómo está ejecutando sus pruebas de procedimiento? ¿De un método de prueba de unidad C #? ¿Un script SQL? ¿Cómo automatizas los informes de resultados?
Matthew Rodatus
@Matthew: una prueba normal de NUnit de un método en mi clase está ejerciendo .NET Framework, según su definición. No es mío, ya que supongo que .NET funciona. Del mismo modo, supongo que SQL Server funciona, y que la SqlCommandclase funciona, y que el transporte TCP funciona. No me he equivocado acerca de eso todavía.
John Saunders
1
@Matthew: si SQL Server y sus funciones y transportes integrados no funcionan, entonces tengo problemas más grandes que si estoy probando unidades o pruebas de integración. Por lo general, supongo que el sistema operativo también funciona, y que la velocidad de la luz es más o menos constante dentro de los marcos en los que operan mis pruebas.
John Saunders
1
@ John No creo que entiendas mi punto, pero bueno.
Matthew Rodatus
0

¿Es esta prueba de integración o prueba unitaria?

¿Dónde se ejecuta la prueba? ¿En la base de datos o mediante un arnés de prueba basado en código (JUnit)?

En la base de datos, entonces es probable que sea una prueba unitaria (ya que es autónoma), un arnés de prueba tipo JUnit y luego se conecta a una base de datos externa y, como tal, una prueba de integración.

Si esto es "solo" pruebas de integración

¿Por qué las citas? Las pruebas de integración no son una especie de bestia que nunca deberías hacer.

¿Alguien tiene sugerencias sobre cómo hacer "pruebas unitarias" reales en estos procedimientos almacenados?

Generalmente encuentro que la única unidad razonable para un procedimiento almacenado es el código de llamada calling y el procedimiento. Así que pruebo la integración del conjunto completo en un conjunto de pruebas que se parecen a las pruebas unitarias.

Una mejor pregunta es por qué te importa [el nombre].

Como le permite dividir las pruebas. Las pruebas de integración tardan más en ejecutarse, requieren una configuración adicional y probablemente acceso a un recurso compartido por muchas pruebas (la base de datos, por ejemplo).

1) El código de llamada tendrá pruebas unitarias adicionales si es necesario.

mlk
fuente
No hay configuración adicional. Toda la configuración está en la prueba misma. Además, estas pruebas son bastante rápidas. Hasta ahora, la preparación en el preámbulo de la prueba no ha tenido que hacer más que eliminar 50 filas y luego insertar otra docena más o menos.
John Saunders
Se inicia una base de datos si no se está ejecutando?
mlk
"Inicia una base de datos"? No, las pruebas usan una cadena de configuración almacenada en el archivo de configuración para las pruebas, y se presume que una vez que se determine la cadena de configuración adecuada, continuará haciendo referencia a una base de datos válida dentro de un servidor de bases de datos válido. En un mundo ideal, estas pruebas podrían ejecutarse después de un despliegue (creación) de una nueva instancia de la base de datos, utilizando el DDL actual, también almacenado en el control de origen. Estamos trabajando hacia ese ideal.
John Saunders
Es un buen ideal para llegar. He estado trabajando para lograr lo mismo por algún tiempo. Mi punto es que tienes tareas de inicio (iniciar una base de datos). Puede (y debe) hacer que sus pruebas no fallen (Afirmar. No es concluyente en MSTest hablar) si las tareas no se han realizado. Esta área de prueba es un área gris de prueba unitaria. Escriba pruebas similares a las pruebas unitarias, pero acepte que son pruebas de integración.
mlk
1
No estoy seguro de lo que quieres decir al iniciar una base de datos. En mi "mundo ideal", el despliegue de una nueva instancia vacía de la base de datos sería parte de la compilación automatizada, no parte de las pruebas.
John Saunders
-1

Microtest es un término útil que puede ayudarlo a eludir el debate sobre la terminología y si su prueba es una prueba unitaria o no.

Una definición común de prueba unitaria incluye que el sistema bajo prueba es una pequeña unidad de funcionalidad y debe poder ejecutar todas las pruebas en la memoria, sin la ayuda de sistemas de archivos, redes o motores de bases de datos . Si necesita un motor de base de datos real para ejecutarlo, entonces no es una prueba unitaria.

Si bien esta definición funciona muy bien para todas las capas de aplicaciones, no es muy útil para la capa de acceso a la base de datos más inferior. Tenemos que reconocer que es especial. Si sus pruebas prueban solo pequeñas unidades de almacenamiento / recuperación / actualización / eliminación, entonces sus pruebas son claramente tan valiosas como las pruebas unitarias "estrictas" escritas en las capas superiores de su sistema.

azheglov
fuente
Aquí es donde existe la controversia: no estoy probando el DAL: estoy probando los procedimientos almacenados y las funciones en la base de datos. Si el DAL es tan simple como configurar parámetros y luego llamar al SP o la función o SELECT, entonces no me molesto en probarlo.
John Saunders