Al aceptar la conveniencia de usar pruebas unitarias en mi C ++ favorito, traté de transferir mi experiencia a TSQL, especialmente porque al nuevo empleador le encanta una iniciativa útil en el terreno y distribuye bollos para ello.
Miré a través de varios
marcos conocidos, llegué a la conclusión de que, por regla general, son voluminosos y aportan una sintaxis adicional que debe estudiarse adicionalmente.
Algunos marcos funcionan a la perfección y complacen a los ojos del gerente, a quien se les muestra, pero tienen una serie de limitaciones que no me gustaron.
Quería implementar todo en TSQL kosher-halal-ortodoxo puro.
De vez en cuando, distrayéndome del desarrollo principal durante varios años sobre el perfeccionamiento de la estructura del guión, decidí compartirlo con ustedes (pero aun así logré producir 3.5 Mb de guiones).
Mis requisitos básicos eran simples: tengo que realizar cualquier prueba unitaria en un archivo sin la necesidad de gestos y herramientas de software especiales, solo hardcore: sqlcmd o MSSMS.
No se realizan cambios en la base de datos en la que se realiza la prueba; todo se revierte al comienzo del script.
Solo uno establece una limitación: la prueba debería funcionar en una base de datos vacía (los datos iniciales pueden serlo), de lo contrario, se cansará de desarmar todas las opciones.
La tarea principal es probar la lógica y mantener la integridad de la lógica.
Para esto, pongo el siguiente encabezado al comienzo de la prueba:
SET QUOTED_IDENTIFIER ON GO PRINT '-------------------------------- CLR Unit tests for Habr Logic ---------------------------------' IF 0 < ( SELECT count(*) FROM device) begin RAISERROR ('FAILED: database must be empty for this unit test', 16, -1 ) end GO
Intento no crear pruebas unitarias más largas que un par de pantallas, aunque esto no es fácil, en el caso de la lógica compleja.
Una prueba unitaria típica tiene este aspecto y tiene 3 partes clave:
BEGIN TRAN TestClr2 declare @test_name sysname = (select TOP 1 name from sys.dm_tran_active_transactions WHERE transaction_type = 1 ORDER BY transaction_begin_time DESC) + ' [fn_calculate_dev_status] record for device has wrong range' BEGIN TRY SET NOCOUNT ON;
- 1. preparar datos para la prueba unitariaAquí podemos completar las tablas necesarias con datos y preparar algunas variables o tablas temporales para no saturar el código en la sección de prueba.
- 2. ejecutar prueba unitariaAquí, como regla, va, ya sea una llamada de función, o un procedimiento, o un cambio de tabla, si probamos la lógica del disparador.
- 3. verificación de resultadosEn esta parte de la prueba, verificamos cómo ha cambiado el estado de los objetos de la base de datos o el resultado del procedimiento de función probado.
Si la función de procedimiento devuelve un registro, lo insertamos en la tabla temporal y ya lo analizamos.
Los resultados agregados y preparados se comparan con el estándar y arrojan una excepción si todo lo demás falla.
Con Oracle, todo es un poco más complicado: no pude escribir y ejecutar la prueba de esa forma y con la misma ideología, sino por una pequeña experiencia, dejamos de apoyar a Oracle para nuestro producto.
Cada prueba unitaria se emite como un procedimiento:
CREATE OR REPLACE PROCEDURE UnitTest9_TRG_JOBLOGDETAIL AS v_message VARCHAR2(255) := 'UnitTest9_TRG_JOBLOGDETAIL: INSERT joblogdetail]- joblogdetail_result not Failed and joblogdetail_endtime is null '; v_maxdate date := '2014/01/01'; v_cnt NUMBER := 0; BEGIN savepoint my_savepoint; <b>
En el mismo archivo de prueba al final, deberá realizar una limpieza de la base de datos de las pruebas creadas y ejecutadas.
commit; / set serveroutput on; SET FEEDBACK OFF; spool C:\dist\test.spl; exec UnitTest_empty_database; exec UnitTest3297_TRGBFR_UDEVICE(1); exec UnitTest5_TRG_BF_UDEVICE; exec UnitTest_3062a; ... spool off; / DROP PROCEDURE UnitTest_3062; DROP PROCEDURE UnitTest_BIRDIESEC_3344; DROP PROCEDURE UnitTest_empty_database; ... SET FEEDBACK ON; commit;
Eso es todo
Luego, solo produce archivos, divididos en categorías del tipo: disparadores, funciones, procedimientos, informes, objetos grandes y especiales de lógica de negocios y, por supuesto, para cada objeto de base de datos.
Casi todos los desarrolladores de bases de datos fruncen el ceño y dicen: ¿por qué debería dejar que los evaluadores hagan esto? Si la base de datos no tiene la lógica de la palabra en absoluto, entonces estoy de acuerdo con ellos, pero si hay mucha, entonces, naturalmente, guardan los nervios, la reputación y el dinero.
Un ejemplo
Tenemos en la interfaz web árboles de conexiones lógicas entre objetos de árbol como América -> Canadá -> Ontario -> Waterloo, Asia -> Japón -> Tokio -> Ebina, es decir, una bola completa de oficinas geográficas.
Cada nodo tiene reglas muy complejas, el usuario o la regla o el generador asigna dispositivos.
Como resultado, incluso las instrucciones descritas en detalle en los pasos demolerán a todos, incluso a aquellos que participaron en la discusión y el desarrollo de esta lógica.
Más de cincuenta pasos de la instrucción con diferentes conjuntos de datos: todo está documentado en detalle.
Cualquier cambio o adición a la lógica es un reloj de verificación manual de que nada se ha roto.
La refactorización de la muerte es similar.
Después de cubrir la lógica con pruebas unitarias, todo se verifica con seda y estoy seguro de que todo funciona como debería.
Cualquier desarrollador de Java que recurra a mí, lanzando truenos y relámpagos (pensando para sí mismo en mis manos torcidas) se implementa fácilmente ejecutando la prueba adecuada.
Un par de minutos y todos están satisfechos. Cualquier cambio de código fatal en mi ausencia me será informado rápidamente por correo.
Naturalmente, como una persona perezosa, decidí automatizar todo para la automatización continua y escribí gachas de avena desde lotes y python.
Le pido que ejecute un poco, en el desarrollo diario de casi una docena de idiomas y entornos entre los que debe saltar, hay una catastrófica falta de tiempo para lamer todo y ponerlo en un aspecto profesional.
No quería hacer todo en Windows PowerShell: nuestros saltos aún se ejecutan aquí y allá en Windows embebido95.
Quería hacer todas las llamadas en Python, pero resultó que algunas construcciones sql (análisis XML dentro de cte) no son compatibles no solo en la biblioteca de python, sino también en .NET, así que comencé la secuencia de comandos a través de sqlcmd.
El código se publica
aquí .
Para ejecutar un ejemplo de trabajo, solo edite 2 archivos: smtppart.py y config.ini: nombre del servidor SMTP, puerto y correo electrónico donde se eliminarán los mensajes de error.
Los scripts primero intentan obtener las últimas actualizaciones de svn (reemplácelas con las suyas propias: git, perforce, ...).
Luego se crea una base limpia a partir de scripts con un nombre aleatorio, se lanzan pruebas unitarias y luego se elimina la base.
La creación de una base de datos de scripts de 80 Mb y pruebas de 3.5 Mb (la parte principal del esquema ya estaba hecha antes de unirme a la compañía, así que probé solo mi parte) se realizan en mi máquina en aproximadamente 15 minutos. Solo tengo tiempo para tomar una taza de café antes del compromiso final.
Si hubo errores, los resultados del error se enviarán por correo electrónico.
La instalación de dependencias se describe en el archivo: readme.txt
Después de cada cambio de código, debe configurar manualmente el hash de código (se verá en la línea de comando) en el archivo config.ini; el mensaje aparecerá incluso si se cambia el código y no se rompe nada, para que pueda controlar los cambios en el código para poder verificar los cambios sin Mi participación previa.

El inicio de todas las pruebas unitarias en el archivo autorun.bat se puede colocar en el
Programador de tareas de Windows para ejecutar 1-2 al día antes de la creación corporativa o después de salir de casa, si algo se rompe por la noche, puede ver lo que sucedió frente al televisor y solucionarlo rápidamente.
Sé que en las pruebas unitarias es más difícil configurar todo, y luego es fácil y agradable escribir pruebas, aunque puede ser difícil y difícil, pero necesario. Buena suerte en las pruebas, espero que mi consejo ayude a alguien.
Estaré encantado de asesorarte si algo se puede mejorar en algún lugar y peinar el código, no juzgues estrictamente.