En su charla TDD, donde todo salió mal , Ian Cooper empuja la intención original de Kent Beck detrás de las pruebas unitarias en TDD (para probar comportamientos, no métodos de clases específicamente) y argumenta a favor de evitar el acoplamiento de las pruebas a la implementación.
En el caso de un comportamiento como save X to some data source
en un sistema con un conjunto típico de servicios y repositorios, ¿cómo podemos probar el almacenamiento de algunos datos a nivel de servicio, a través del repositorio, sin acoplar la prueba a los detalles de implementación (como llamar a un método específico )? ¿Evitar este tipo de acoplamiento en realidad no vale la pena el esfuerzo / mal de alguna manera?
unit-testing
tdd
coupling
Andy Hunt
fuente
fuente
Respuestas:
Su ejemplo específico es un caso que generalmente tiene que probar comprobando si se llamó a cierto método, porque
saving X to data source
significa comunicarse con una dependencia externa , por lo que el comportamiento que debe probar es que la comunicación se produce como se esperaba .Sin embargo, esto no es algo malo. Las interfaces de límites entre su aplicación y sus dependencias externas no son detalles de implementación , de hecho, están definidas en la arquitectura de su sistema; lo que significa que tal límite no es probable que cambie (o si debe hacerlo, sería el tipo de cambio menos frecuente). Por lo tanto, acoplar sus pruebas a una
repository
interfaz no debería causarle demasiados problemas (si lo hace, considere si la interfaz no le está robando responsabilidades a la aplicación).Ahora, considere solo las reglas comerciales de una aplicación, desacopladas de la interfaz de usuario, las bases de datos y otros servicios externos. Aquí es donde debe ser libre de cambiar tanto la estructura como el comportamiento del código. Aquí es donde las pruebas de acoplamiento y los detalles de implementación lo obligarán a cambiar más código de prueba que el código de producción, incluso cuando no haya cambios en el comportamiento general de la aplicación. Aquí es donde las pruebas en
State
lugar deInteraction
ayudarnos a ir más rápido.PD: No es mi intención decir si la prueba por estado o interacciones es la única forma verdadera de TDD: creo que es una cuestión de utilizar la herramienta adecuada para el trabajo correcto.
fuente
Mi interpretación de esa charla es:
No se menciona en la charla, pero creo que el contexto asumido para el consejo es algo como:
Por lo tanto, probar un componente es el mayor alcance posible en el que algo todavía se puede llamar razonablemente prueba unitaria. Esto es bastante diferente de cómo algunas personas, especialmente académicos, usan el término. No se parece en nada a los ejemplos del tutorial típico de la herramienta de prueba unitaria. Sin embargo, coincide con su origen en las pruebas de hardware; las placas y los módulos se prueban en la unidad, no los cables y tornillos. O al menos no construyes un Boeing simulado para probar un tornillo ...
Extrapolando de eso, y arrojando algunos de mis propios pensamientos,
Si lo hace de manera adecuada y limpia, apenas necesita una herramienta de burla; solo se usa unas pocas veces por sistema.
Una base de datos es generalmente un colaborador, por lo que se falsifica en lugar de burlarse. Sería doloroso implementarlo a mano; Afortunadamente, tales cosas ya existen .
El patrón de prueba básico es realizar una secuencia de operaciones (por ejemplo, guardar y volver a cargar un documento); confirmar que funciona Esto es lo mismo que para cualquier otro escenario de prueba; Es probable que ningún cambio en la implementación (en funcionamiento) provoque que tal prueba falle.
La excepción es cuando los registros de la base de datos se escriben pero nunca son leídos por el sistema bajo prueba; por ejemplo, registros de auditoría o similares. Estas son salidas, por lo que se deben burlar. El patrón de prueba es hacer alguna secuencia de operaciones; confirme que se llamó a la interfaz de auditoría con los métodos y argumentos especificados
Tenga en cuenta que incluso aquí, siempre que esté utilizando una herramienta de burla de tipo seguro como mockito , cambiar el nombre de un método de interfaz no puede causar una falla de prueba. Si utiliza un IDE con las pruebas cargadas, se refactorizará junto con el cambio de nombre del método. Si no lo hace, la prueba no se compilará.
fuente
Mi sugerencia es utilizar un enfoque de prueba basado en estado:
DADO Tenemos el DB de prueba en un estado conocido
CUANDO se llama al servicio con argumentos X
ENTONCES Afirme que la base de datos ha cambiado de su estado original al estado esperado llamando a métodos de repositorio de solo lectura y verificando sus valores devueltos
Al hacerlo, no confía en ningún algoritmo interno del servicio, y es libre de refactorizar su implementación sin tener que cambiar las pruebas.
El único acoplamiento aquí es con la llamada al método de servicio y las llamadas al repositorio necesarias para leer los datos de la base de datos, lo cual está bien.
fuente