Estoy de acuerdo con mucho de lo anterior, en relación con las pruebas unitarias. Sin embargo, creo que es importante plantear que el uso de repositorios falsos y pruebas unitarias no le da el mismo nivel de pruebas que una prueba de integración de DB.
Por ejemplo, nuestras bases de datos a menudo tienen eliminaciones en cascada incorporadas directamente en el esquema. En este caso, eliminar una entidad primaria en un agregado eliminará automáticamente todas las entidades secundarias. Sin embargo, esto no se aplicaría automáticamente en un repositorio simulado que no estaba respaldado por una base de datos física con estas reglas de negocio (a menos que haya creado todas esas reglas en el simulacro). Esto es importante porque si alguien viene y cambia el diseño de mi esquema, necesito que rompa mis pruebas para poder ajustar el código/esquema en consecuencia. Aprecio que esto sea Pruebas de integración y no Pruebas unitarias, pero pensé que valía la pena mencionarlo.
Mi opción preferida es crear una base de datos maestra de diseño que contenga datos de muestra (el mismo tipo de datos que crearía en sus simulacros). Durante el inicio de cada ejecución de prueba, tengo un script automatizado que crea una copia de seguridad del MasterDB y lo restaura en "TestDB" (que usan todas mis pruebas). De esa forma, mantengo un repositorio de datos de prueba limpios en el Máster que se recrea en cada ejecución de prueba. Mis pruebas pueden jugar con los datos y probar todos los escenarios necesarios.
Cuando depuro la aplicación, tengo otra secuencia de comandos que realiza una copia de seguridad y restaura la base de datos maestra a una base de datos DEV. Puedo jugar con los datos aquí también sin preocuparme por perder mis datos de muestra. Normalmente, no ejecuto este script en particular en cada sesión debido a la demora a la espera de que se vuelva a crear el DB. Puedo ejecutarlo una vez al día y luego jugar/depurar la aplicación durante todo el día. Si, por ejemplo, borro todos los registros de una tabla como parte de mi depuración, ejecutaría la secuencia de comandos para recrear la DevDB cuando haya terminado.
Estos pasos parecen que agregarían una gran cantidad de tiempo al proceso, pero en realidad, no es así. Nuestra aplicación actualmente tiene alrededor de 3500 pruebas, y aproximadamente 3000 de ellas acceden a la base de datos en algún momento. La copia de seguridad y restauración de la base de datos generalmente demora alrededor de 10-12 segundos al inicio de cada ejecución de prueba. Y dado que todo el conjunto de pruebas solo se ejecuta con el registro TFS, no nos importa si tenemos que esperar un poco más de todos modos. En un día normal, nuestro conjunto de pruebas completo tarda entre 15 y 20 minutos en ejecutarse.
Aprecio y acepto que las pruebas de integración son mucho más lentas que las pruebas unitarias (debido a la necesidad inherente de usar una base de datos real) pero representan más de cerca la aplicación del "mundo real". Por ejemplo, los repositorios falsos no devuelven los códigos de error de la base de datos, no tienen tiempo de espera, no se bloquean, no se quedan sin espacio en el disco, etc.
Las pruebas unitarias son correctas por simple cálculos, reglas comerciales básicas, etc. y ciertamente son absolutamente la mejor opción para la mayoría de las operaciones que no involucran el acceso al DB (u otro recurso). Pero no creo que sean tan valiosos como las pruebas de integración: la gente habla mucho sobre pruebas unitarias, pero se dice poco acerca de las pruebas de integración.
Espero que los apasionados de las pruebas unitarias envíen llamas a mi manera para esto. Está bien, solo trato de traer un poco de equilibrio y recordar a la gente que los proyectos que están llenos de pruebas unitarias pasadas aún pueden fallar en el momento en que los implemente en el campo.
Utilizo ese mismo código de burla de contexto de datos y funciona muy bien –