¿Qué es una prueba de unidad , realmente? ¿Y hay realmente una gran dicotomía en juego aquí?
Trabajamos en un campo donde la lectura, literalmente, un poco después del final de un búfer puede bloquear totalmente un programa, o hacer que produzca un resultado totalmente inexacto, o como lo demuestra el reciente error TLS "HeartBleed", supuestamente Sistema seguro abierto 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.
¿Una prueba de unidad es una prueba que confirma, por ejemplo, que una reserva se publica correctamente en tres sistemas diferentes, se crea una entrada de registro y se envía una confirmación por correo electrónico?
Voy a decir no . Esa es una prueba de integración . Y los que 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 se debe dividir en bloques de construcción simples y comprobables, también conocidos como "unidades".
Por lo tanto, una prueba de unidad debe tener un alcance muy limitado.
Lo que implica que el código probado por la prueba de la unidad debe tener un alcance muy limitado.
Lo que implica además que uno de los pilares de un buen diseño es dividir su problema complejo en partes más pequeñas y de un solo propósito (en la medida de lo posible) que puedan probarse en un aislamiento relativo entre sí.
Lo que terminas con es un sistema hecho de componentes de base confiables, y sabes si alguna de esas unidades fundamentales de código se rompe porque has escrito pruebas simples, pequeñas y de alcance limitado para decirte exactamente eso.
En muchos casos, es probable que también deba realizarse varias pruebas por unidad. Las pruebas en sí deben ser simples, probando una y solo una conducta en la medida de lo posible.
La noción de una "prueba unitaria" que prueba una lógica compleja, no trivial y elaborada es, creo, un poco de oxímoron.
Entonces, si ese tipo de desglose deliberado del diseño ha tenido lugar, entonces, ¿cómo es posible que una prueba unitaria en el mundo comience a producir falsos positivos, 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 dominantes no obvios 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 necesita ser examinado y corregido.
Es posible que algunas de esas unidades (muchas de ellas) deban probarse mediante el uso de objetos simulados, pero eso no significa que tenga que escribir pruebas más complejas o elaboradas.
Volviendo a mi ejemplo ideado de un sistema de reservas, realmente no puede enviar solicitudes a una base de datos de reservas en vivo o servicio de terceros (o incluso una instancia "dev" de él) cada vez que unidad prueba tu código.
Entonces, usas simulacros que presentan el mismo contrato de interfaz. Luego, las pruebas pueden validar el comportamiento de un fragmento de código determinista relativamente pequeño. El verde en toda la pizarra luego te dice que los bloques que conforman tu base no están rotos.
Pero la lógica de las pruebas de unidades individuales sigue siendo tan simple como sea posible.