Estoy comenzando un nuevo proyecto y estoy intentando utilizar TDD para impulsar el diseño. He estado presionando durante años, y finalmente obtuve la aprobación para dedicar más tiempo a este proyecto para usarlo mientras aprendo cómo hacerlo correctamente.
Este es un nuevo módulo, para vincularlo a un sistema existente. En la actualidad, todo el acceso a los datos se realiza a través de servicios web, que en su mayor parte son solo una envoltura delgada sobre los procedimientos almacenados de la base de datos.
Un requisito es que para una tienda determinada, devuelvo todas las órdenes de compra que se consideran válidas para esta aplicación. Una orden de compra se considera válida si su fecha de envío cae dentro de un rango determinado desde la fecha de apertura de las tiendas (esto es para nuevas tiendas).
Ahora, no puedo poner esta lógica en el código de la aplicación, ya que no voy a recuperar un millón de pedidos de compra solo para obtener la docena que se aplica a esta tienda dada la restricción anterior.
Estaba pensando, podría pasar el rango de fechas a un proceso GetValidPOs y hacer que use esos valores para devolver los PO válidos. Pero, ¿qué pasa si agregamos otro requisito a lo que se considera una orden de compra válida?
¿Y cómo pruebo esto y verifico que sigue funcionando? No estamos utilizando un ORM, y es poco probable que suceda. Y no puedo llamar al DB en mi prueba.
Estoy atascado.
Mi otro pensamiento es tener algunos simulacros que devuelven datos válidos, otros que devuelven algunos datos incorrectos y hacer que el repositorio local arroje una excepción si se producen datos incorrectos y compruebe que la excepción se genera si el proceso GetValidPOs devuelve datos no válidos (o el simulacro utilizado en las pruebas).
¿Esto tiene sentido? ¿O hay un mejor camino?
ACTUALIZACIÓN: Parece que puedo usar EF. Ahora solo necesito descubrir cómo usarlo y hacerlo comprobable, al mismo tiempo que puedo confiar en los procedimientos almacenados y la dificultad de tener datos dispersos en varias bases de datos.
fuente
Respuestas:
Esta es una desventaja importante de los procedimientos almacenados en la era de TDD. Tienen algunas ventajas reales, incluso ahora, pero por definición cualquier prueba que ejercita un proceso almacenado no es una prueba unitaria; Es una prueba de integración en el mejor de los casos.
La solución habitual, suponiendo que la arquitectura no puede cambiar para usar un ORM en su lugar, es no poner estas pruebas en el conjunto de pruebas unitarias; en su lugar, ponga las pruebas en un paquete de integración. Todavía puede ejecutar la prueba cada vez que desee verificar que funciona, pero debido a que el costo inherente a la configuración de la prueba (inicializar una base de datos con los datos de prueba adecuados) es alto y toca los recursos, es posible que el agente de prueba de unidad de su robot de construcción no tener acceso a, no debería estar en el conjunto de pruebas unitarias.
Todavía puede probar el código de la unidad que requiere los datos, abstrayendo cualquier cosa que no pueda probar la unidad (clases ADO.NET) en una clase DAO que luego pueda burlarse. Luego, puede verificar que las llamadas esperadas se realicen consumiendo código y reproduciendo comportamientos del mundo real (como no encontrar resultados) que permitan probar varios casos de uso. Sin embargo, la configuración real de SqlCommand para llamar al proceso almacenado es prácticamente lo último que puede probar unitariamente, separando la creación de comandos de la ejecución de comandos y burlándose del ejecutor de comandos. Si esto suena como una gran separación de preocupaciones, puede ser; recuerde, "no hay problema que no pueda ser resuelto por otra capa de indirección, excepto por tener demasiadas capas de indirección". En algún momento debes decir "suficiente; simplemente no puedo hacer una prueba unitaria de esto, nosotros '
Otras opciones:
Pruebe el proceso almacenado utilizando una instancia de DBMS "de corta duración" como SQLite. Por lo general, es más fácil hacer esto cuando se usa un ORM, pero la prueba se puede hacer "en memoria" (o con un archivo de base de datos preestablecido incluido con el conjunto de pruebas). Todavía no es una prueba unitaria, pero se puede ejecutar con un alto grado de aislamiento (el DBMS es parte del proceso de ejecución y no es algo a lo que se conecta de forma remota que puede estar en el medio del conjunto de pruebas conflictivas de otra persona). La desventaja es que los cambios en el proceso almacenado pueden ocurrir en la producción sin que la prueba refleje el cambio, por lo que debe ser disciplinado para asegurarse de que el cambio se realice primero en un entorno de prueba.
Considere actualizar a un ORM. Un ORM con un proveedor de Linq (prácticamente todos los de uso común tienen uno) le permitiría definir la consulta como una declaración de Linq; esa declaración se puede dar a un Repositorio simulado que tiene una colección en memoria de datos de prueba para aplicarlo. Por lo tanto, puede verificar que la consulta sea correcta sin siquiera tocar la base de datos (aún debe ejecutar la consulta en un entorno de integración, para probar que el proveedor de Linq puede digerir correctamente la consulta).
fuente
Mi consejo es dividir y conquistar . Olvídese de la base de datos y la persistencia por el momento y concéntrese en probar implementaciones falsas de sus repositorios u objetos de acceso a datos.
Me burlaría del repositorio que devuelve las órdenes de compra. Crea un simulacro con veinte órdenes de compra impares.
Aplique una llamada a GetValidPOs para que llame a su simulación, en lugar del procedimiento de base de datos.
Necesita una prueba unitaria para asegurarse de que los datos correctos se devuelven de un simulacro.
También necesita una prueba de integración para asegurarse de que se devuelven los datos correctos de una base de datos. La prueba de integración requeriría cierta configuración y limpieza. Por ejemplo, antes de ejecutar la prueba de integración, siembra tu base de datos ejecutando un script. Verifique que su script haya funcionado. Consulte la base de datos llamando a sus procedimientos almacenados. Verifique que sus resultados sean correctos. Limpia la base de datos.
Como ya dije, necesita un simulacro que devuelva al menos algunos datos que puede consultar.
Cuando consulta datos desea asegurarse de que su sistema pueda manejar las excepciones con gracia. Por lo tanto, se burla del comportamiento para que arroje excepciones en ciertos escenarios. Luego escribe pruebas para asegurarse de que su sistema pueda manejar estas excepciones con gracia.
fuente
Del mismo modo que la prueba unitaria de Java o Javascript significa escribir pruebas unitarias utilizando el lenguaje Java para Java, y la prueba unitaria de funciones Javascript con Javascript, escribir pruebas automatizadas para guiarlo a escribir procedimientos almacenados significa que la biblioteca de pruebas unitarias que está buscando se basa en procedimientos
Dicho de otra manera, use procedimientos almacenados para probar los procedimientos almacenados porque:
Al igual que TDD en un idioma OO, desea que su prueba unitaria configure solo una fila de datos para probar lo que necesita para el procedimiento (minimalismo, solo tiene lo que necesita su prueba simple). El resultado de esto es que tendrá varias pruebas unitarias simples para cada procedimiento almacenado. Estas pruebas simples serán más fáciles de mantener que tener pruebas complicadas que dependen de un gran conjunto de datos que no se asigna fácilmente a lo que la prueba realmente necesita.
fuente