Sigo TDD religiosamente. Mis proyectos suelen tener una cobertura de prueba del 85% o mejor, con casos de prueba significativos.
Trabajo mucho con HBase , y la interfaz principal del cliente, HTable, es muy difícil de burlar. Me toma 3 o 4 veces más tiempo escribir mis pruebas unitarias que escribir pruebas que usan un punto final en vivo.
Sé que, filosóficamente, las pruebas que usan simulacros deben tener prioridad sobre las pruebas que usan un punto final en vivo. Pero burlarse de HTable es un dolor grave, y no estoy realmente seguro de que ofrezca una gran ventaja sobre las pruebas contra una instancia de HBase en vivo.
Todos en mi equipo ejecutan una instancia de HBase de un solo nodo en su estación de trabajo, y tenemos instancias de HBase de un solo nodo ejecutándose en nuestros cuadros de Jenkins, por lo que no es un problema de disponibilidad. Las pruebas de punto final en vivo obviamente tardan más en ejecutarse que las pruebas que usan simulacros, pero realmente no nos importa.
En este momento, escribo pruebas de punto final en vivo y pruebas simuladas para todas mis clases. Me encantaría deshacerme de los simulacros, pero no quiero que la calidad disminuya como resultado.
¿Qué piensan todos ustedes?
fuente
Respuestas:
Mi primera recomendación sería no burlarse de tipos que no son de su propiedad . Usted mencionó que HTable es una verdadera molestia: tal vez debería envolverlo en un Adaptador que expone el 20% de las características de HTable que necesita y burlarse del envoltorio donde sea necesario.
Dicho esto, supongamos que estamos hablando de tipos que todos poseen. Si sus pruebas basadas en simulacros se centran en escenarios de ruta feliz donde todo transcurre sin problemas, no perderá nada abandonándolos porque sus pruebas de integración probablemente ya estén probando exactamente las mismas rutas.
Sin embargo, las pruebas aisladas se vuelven interesantes cuando comienzas a pensar cómo debería reaccionar tu sistema bajo prueba a cada pequeña cosa que podría suceder como se define en el contrato de su colaborador, independientemente del objeto concreto real con el que esté hablando. Eso es parte de lo que algunos llaman corrección básica . Podría haber muchos de esos pequeños casos y muchas más combinaciones de ellos. Aquí es donde las pruebas de integración comienzan a ser pésimas, mientras que las pruebas aisladas seguirán siendo rápidas y manejables.
Para ser más concreto, ¿qué sucede si uno de los métodos de su adaptador HTable devuelve una lista vacía? ¿Qué pasa si devuelve nulo? ¿Qué pasa si arroja una excepción de conexión? Debe definirse en el contrato del Adaptador si cualquiera de esas cosas puede suceder, y cualquiera de sus consumidores debe estar preparado para lidiar con estas situaciones , de ahí la necesidad de pruebas para ellos.
En resumen: no verá ninguna disminución de la calidad al eliminar sus pruebas basadas en simulacros si probaron exactamente las mismas cosas que sus pruebas de integración . Sin embargo, tratar de imaginar pruebas aisladas adicionales (y pruebas de contrato ) puede ayudarlo a pensar ampliamente en sus interfaces / contratos y aumentar la calidad al abordar defectos que habrían sido difíciles de pensar y / o lentos para probar con las pruebas de integración.
fuente
Creo que por lo menos, eso es un punto de corriente continua controversia entre los defensores de TDD.
Mi opinión personal va más allá de eso para decir que una prueba simulada es principalmente una forma de representar una forma de contrato de interfaz ; idealmente se rompe (es decir, falla) si y solo si cambia la interfaz . Y como tal, en lenguajes razonablemente fuertemente tipados como Java, y cuando se usa una interfaz definida explícitamente, es casi completamente superfluo: el compilador ya le habrá dicho si ha cambiado la interfaz.
La principal excepción es cuando está utilizando una interfaz muy genérica, quizás basada en anotaciones o reflexiones, que el compilador no puede supervisar automáticamente de manera útil. Incluso entonces, debe verificar si hay una manera de hacer la validación mediante programación (por ejemplo, una biblioteca de verificación de sintaxis SQL) en lugar de hacerlo manualmente con simulacros.
Es el último caso que está haciendo cuando prueba con una base de datos local 'en vivo'; la implementación de htable se inicia y aplica una validación mucho más completa del contrato de interfaz de lo que se podría pensar escribir a mano.
Desafortunadamente, un uso mucho más común de las pruebas simuladas es la prueba que:
Tales pruebas, por supuesto, deben eliminarse a la vista.
fuente
¿Cuánto tiempo tarda más en ejecutarse una prueba basada en puntos finales que una prueba simulada? Si es significativamente más largo, entonces sí, vale la pena invertir su tiempo de redacción de pruebas para hacer que las pruebas unitarias sean más rápidas, porque tendrá que ejecutarlas muchas, muchas veces. Si no es significativamente más largo, a pesar de que las pruebas basadas en puntos finales no son pruebas unitarias "puras", siempre y cuando estén haciendo un buen trabajo al probar la unidad, no hay razón para ser religiosos al respecto.
fuente
Estoy completamente de acuerdo con la respuesta de guillaume31, ¡nunca te burles de los tipos que no tienes!
Normalmente, un problema en la prueba (burlándose de una interfaz compleja) refleja un problema en su diseño. Quizás necesite algo de abstracción entre su modelo y su código de acceso a datos, por ejemplo, utilizando una arquitectura hexagonal y un patrón de repositorio, es la forma más habitual de resolver este tipo de problemas.
Si desea hacer una prueba de integración para verificar las cosas, haga una prueba de integración, si desea hacer una prueba unitaria porque está probando su lógica, haga una prueba unitaria y aísle la persistencia. Pero hacer una prueba de integración porque no sabe cómo aislar su lógica de un sistema externo (o porque aislar es un dolor) es un gran olor, está eligiendo la integración sobre la unidad por una limitación en su diseño, no por una necesidad real para probar la integración.
Eche un vistazo a esta charla de Ian Cooper: http://vimeo.com/68375232 , habla sobre la arquitectura hexagonal y las pruebas, habla sobre cuándo y qué burlarse, una charla realmente inspirada que resuelve muchas preguntas como la suya sobre la TDD real .
fuente
TL; DR : a mi modo de ver, depende de cuánto esfuerzo termine gastando en pruebas y de si hubiera sido mejor gastar más en su sistema real.
Versión larga:
Algunas buenas respuestas aquí, pero mi opinión al respecto es diferente: las pruebas son una actividad económica que debe pagarse por sí misma, y si el tiempo que pasa no se devuelve en el desarrollo y la confiabilidad del sistema (o cualquier otra cosa que desee obtener) de pruebas), entonces puede estar haciendo una mala inversión; estás en el negocio de construir sistemas, no de escribir pruebas. Por lo tanto, reducir el esfuerzo para escribir y mantener pruebas es crucial.
Por ejemplo, algunos valores principales que obtengo de las pruebas son:
La prueba contra un punto final en vivo aún debería proporcionar estos.
Algunos inconvenientes para probar contra un punto final en vivo:
Si estuviera en esta situación, y los inconvenientes no parecieran ser un problema, mientras que burlarme del punto final ralentizó considerablemente mi escritura de prueba, probaría contra un punto final en vivo en un instante, siempre y cuando me asegure de verifique nuevamente después de un tiempo para ver que los inconvenientes no resultan ser un problema en la práctica.
fuente
Desde la perspectiva de la prueba, hay algunos requisitos que son imprescindibles:
Ese es un gran desafío cuando se conecta a cualquier fuente que mantenga el estado fuera de sus pruebas. No es TDD "puro", pero el equipo de Ruby on Rails resolvió este problema de una manera que podría adaptarse para sus propósitos. El marco de prueba de rails funcionó de esta manera:
Todo este trabajo se incorporó al arnés de prueba y funciona razonablemente bien. Hay mucho más, pero los conceptos básicos son suficientes para esta conversación.
En los diferentes equipos con los que he trabajado a lo largo del tiempo, tomaríamos decisiones que promoverían la prueba del código, incluso si no fuera la ruta más correcta. Idealmente, envolveríamos todas las llamadas a un almacén de datos con el código que controlamos. En teoría, si alguno de estos viejos proyectos obtuviera nuevos fondos, podríamos retroceder y pasar de la base de datos vinculada a Hadoop al concentrar nuestra atención en solo un puñado de clases.
Los aspectos importantes son no meterse con los datos de producción y asegurarse de que realmente está probando lo que cree que está probando. Es realmente importante poder restablecer el servicio externo a una línea base conocida bajo demanda, incluso desde su código.
fuente