¿Qué es realmente una prueba unitaria ? ¿Y hay realmente una gran dicotomía en juego aquí?
Trabajamos en un campo donde leer literalmente un poco más allá del final de un búfer puede bloquear completamente un programa, o producir un resultado totalmente inexacto, o como lo demuestra el reciente error TLS "HeartBleed", pone un sistema supuestamente seguro abrir sin producir ninguna evidencia directa de la falla.
Es imposible eliminar toda la complejidad de estos sistemas. Pero nuestro trabajo es, en la medida de lo posible, minimizar y gestionar esa complejidad.
¿Es una prueba unitaria una prueba que confirma, por ejemplo, que una reserva se ha publicado con éxito en tres sistemas diferentes, se crea una entrada de registro y se envía una confirmación por correo electrónico?
Voy a decir que no . Esa es una prueba de integración . Y esos definitivamente tienen su lugar, pero también son un tema diferente.
Una prueba de integración funciona para confirmar la función general de una "característica" completa. Pero el código detrás de esa característica debe desglosarse en bloques de construcción simples y comprobables, también conocidos como "unidades".
Por lo tanto, una prueba unitaria debe tener un alcance muy limitado.
Lo que implica que el código probado por la prueba unitaria debe tener un alcance muy limitado.
Lo que implica además que uno de los pilares del buen diseño es dividir su complejo problema en piezas más pequeñas y de un solo propósito (en la medida de lo posible) que se pueden probar en relativo aislamiento entre sí.
Lo que termina es un sistema hecho de componentes básicos confiables, y usted sabe si alguna de esas unidades fundamentales de código se rompe porque ha escrito pruebas simples, pequeñas y de alcance limitado para decirle exactamente eso.
En muchos casos, probablemente también debería tener varias pruebas por unidad. Las pruebas en sí mismas deberían ser simples, probando uno y solo un comportamiento en la medida de lo posible.
La noción de una "prueba unitaria" que prueba una lógica compleja, no trivial es, creo, un poco un oxímoron.
Entonces, si se ha producido ese tipo de ruptura deliberada del diseño, ¿cómo podría una prueba de unidad comenzar a producir falsos positivos de repente, a menos que la función básica de la unidad de código probada haya cambiado? Y si eso ha sucedido, es mejor que creas que hay algunos efectos no evidentes en juego. Su prueba rota, la que parece estar produciendo un falso positivo, en realidad le advierte que algún cambio ha roto un círculo más amplio de dependencias en la base del código, y debe ser examinado y reparado.
Es posible que algunas de esas unidades (muchas de ellas) deban probarse utilizando objetos simulados, pero eso no significa que tenga que escribir pruebas más complejas o elaboradas.
Volviendo a mi ejemplo ingenioso de un sistema de reservas, realmente no se pueden enviar solicitudes a una base de datos de reservas en vivo o un servicio de terceros (o incluso una instancia "dev" de ella) cada vez que prueba el código de su unidad .
Entonces usas simulacros que presentan el mismo contrato de interfaz. Las pruebas pueden validar el comportamiento de un fragmento de código relativamente pequeño y determinista. Verde en todo el tablero luego te dice que los bloques que componen tu base no están rotos.
Pero la lógica de las pruebas unitarias individuales sigue siendo lo más simple posible.