¿Necesito una prueba unitaria si ya tengo una prueba de integración?

47

Si ya tengo una prueba de integración para mi programa, y ​​todos pasaron, tengo la sensación de que funcionará. Entonces, ¿cuáles son las razones para escribir / agregar pruebas unitarias? Como de todos modos ya tengo que escribir pruebas de integración, me gustaría escribir solo pruebas unitarias para partes que no están cubiertas por las pruebas de integración.

Lo que sé, el beneficio de la prueba unitaria sobre la prueba de integración son

  • Pequeño y, por lo tanto, rápido de ejecutar (pero agregar una nueva unidad para probar algo ya está probado por la prueba de integración significa que mi traje de prueba total se hace más grande y más largo para ejecutarse)
  • Localice el error más fácilmente porque solo prueba una cosa (pero puedo comenzar a escribir la prueba unitaria para verificar cada parte individual cuando falla mi prueba de integración)
  • Encuentra un error que puede no quedar atrapado en la prueba de integración. por ejemplo, enmascarar / compensar errores. (pero si mi integración prueba todos los pases, lo que significa que mi programa funcionará incluso si existe algún error oculto. Por lo tanto, encontrar / corregir estos errores no son realmente de alta prioridad a menos que comiencen a romper futuras pruebas de integración o causen problemas de rendimiento)

Y siempre queremos escribir menos código, pero las pruebas de unidades de escritura necesitan mucho más código (principalmente objetos simulados de configuración). La diferencia entre algunas de mis pruebas unitarias y las pruebas de integración es que en las pruebas unitarias, uso un objeto simulado, y en las pruebas de integración, uso un objeto real. Que tienen mucha duplicación y no me gusta el código duplicado, incluso en las pruebas porque esto agrega gastos generales para cambiar el comportamiento del código (la herramienta de refactorización no puede hacer todo el trabajo todo el tiempo).

Bryan Chen
fuente
Solo por curiosidad, ¿cuánta cobertura tienen sus pruebas de integración? Además, si tiene alguna lógica compleja, ¿las pruebas de integración las cubren todas o solo una parte y qué partes, importantes para el negocio o al azar?
civan
Esta pregunta parece ambigua. Digamos que tengo un método de controlador Rails que llama a un interactor ( github.com/collectiveidea/interactor ). Decidí escribir pruebas de integración para mi método de controlador (porque sin ellas no puedo confiar en que mi punto final API funcione). Aquí hay al menos dos preguntas: (1) también debería escribir pruebas unitarias para mis métodos de controlador (es decir, debería escribir pruebas unitarias que prueben el mismo comportamiento que mis pruebas de integración), y (2) también debería escribir pruebas unitarias para mi interactor? Contestaría estas dos preguntas de manera diferente en ciertos contextos comerciales.
Daniel

Respuestas:

33

Ha presentado buenos argumentos a favor y en contra de las pruebas unitarias. Así que hay que preguntarse, " ¿Veo el valor de los argumentos positivos que compensan los costes en los negativos? " Desde luego, hacer:

  • Pequeño y rápido es un buen aspecto de las pruebas unitarias, aunque de ninguna manera es el más importante.
  • Locating-bug [s] -easier es extremadamente valioso. Muchos estudios de desarrollo de software profesional han demostrado que el costo de un error aumenta abruptamente a medida que envejece y baja por la tubería de entrega de software.
  • Encontrar errores enmascarados es valioso. Cuando sepa que un componente en particular tiene todos sus comportamientos verificados, puede usarlo de manera que no se haya usado previamente, con confianza. Si la única verificación es a través de pruebas de integración, solo sabrá que sus usos actuales se comportan correctamente.
  • Burlarse es costoso en casos del mundo real, y mantener simulacros es doble. De hecho, al burlarse de objetos o interfaces "interesantes", ¡incluso podría necesitar pruebas que verifiquen que sus objetos simulados modelen correctamente sus objetos reales!

En mi libro, los pros superan a los contras.

Ross Patterson
fuente
2
¿No es burlarse más barato en casos del mundo real? Solo está estableciendo expectativas de los mensajes que recibe el simulacro y especificando qué devolverá.
Dogweather
10
@Dogweather Mocks funciona bien cuando se crea por primera vez. A medida que pasa el tiempo y se cambia el objeto real, las simulaciones tienen que cambiar con él. Después de 10 años y 6,000 pruebas unitarias en el camino, es muy difícil saber que sus pruebas "exitosas" son realmente exitosas.
Ross Patterson
1
Por otro lado, que "10 años y 6,000 pruebas unitarias" son números de experiencia personal, no una hipérbole.
Ross Patterson
3
Comencé a escribir pruebas automatizadas de desarrollador (unidad e integración, pero principalmente la última) en 2004 o 2005, y desarrollé una biblioteca de simulación avanzada para Java. Muchas veces vi varias pruebas de integración quebradas por la misma razón (como un cambio en la base de datos o un cambio en la red), y a veces escribo pruebas de integración de "nivel inferior" para componentes reutilizables, pero aún así, prefiero tener solo pruebas de integración. Las pruebas unitarias aisladas con burlas, la mayoría de las veces, simplemente no valen la pena; Aplico burla solo como ayuda para las pruebas de integración.
Rogério
Tu última viñeta parece contradecir el argumento que estás haciendo. En este punto, está argumentando en contra de escribir simulaciones innecesarias, lo cual es un argumento en contra de escribir pruebas unitarias para partes que ya están cubiertas por pruebas de integración. Sin embargo, el argumento de su argumento está a favor de escribir pruebas unitarias para partes que ya están cubiertas por pruebas de integración. ¿Podría aclarar su intención aquí @RossPatterson?
Daniel
8

No veo mucho valor en volver a implementar un caso de prueba de integración existente como prueba unitaria.

Las pruebas de integración son a menudo mucho más fáciles de escribir para aplicaciones no tdd heredadas porque generalmente las funcionalidades a probar están estrechamente acopladas, por lo que las unidades de prueba aisladas (= prueba de unidad) pueden ser difíciles / costosas / imposibles.

> Then what are the reasons to write/add unit tests?

En mi opinión, el desarrollo basado en pruebas es más efectivo si escribe las pruebas unitarias antes del código real. De esta manera, el código que cumple las pruebas se separa claramente con un mínimo de referencias externas que es fácilmente comprobable.

Si el código ya existe sin las pruebas unitarias, generalmente es mucho trabajo adicional escribir las pruebas unitarias después porque el código no se escribió para una prueba fácil.

Si hace TDD, el código automáticamente se puede comprobar fácilmente.

k3b
fuente
2
Si tengo una aplicación heredada con no unit-tests, y quiero incluirla unit-testspara ciertas partes, ¿crees que es mejor escribir primero integration testsel código heredado? Una vez que está escrito, ¿puede desacoplar el acoplamiento estrecho y crear funciones con interfaces que se puedan probar? Como ya tiene el integration-testescrito, puede verificar en cada paso de la refactorización, que la nueva versión del código todavía funciona como se desea.
alpha_989
2
@ alpha_989, esto es en mi humilde opinión y estoy dispuesto a escuchar otras ideas, pero preferiría las Pruebas de integración a las Pruebas de unidad para el código heredado. En ambos casos, debe asegurarse de que los métodos funcionan correctamente antes de agregar cualquier tipo de prueba, pero la Prueba de integración garantiza que las expectativas generales de los métodos funcionen en oposición a los elementos de código individuales.
Britt Wescott
5

Las pruebas de integración solo deben verificar que varios componentes funcionan juntos como se esperaba. Se debe verificar si la lógica de los componentes individuales es precisa o no mediante pruebas unitarias.
La mayoría de los métodos tienen varias rutas de ejecución posibles; piense en las variables de entrada de if-then-else, con valores inesperados o simplemente incorrectos, etc. Por lo general, los desarrolladores tienden a pensar solo en el camino feliz: el camino normal que no sale mal. Pero en lo que respecta a esas otras rutas, tiene dos opciones: puede dejar que su usuario final explore esas rutas a través de las acciones que realizan en la interfaz de usuario y esperar que no bloqueen su aplicación, o puede escribir pruebas unitarias que afirmen el comportamiento de esos otros caminos y tomar medidas cuando sea necesario.

Stefan Billiet
fuente
4

Algunas de las razones que ha señalado en su pregunta son realmente importantes y, por sí mismas, podrían justificar el caso a favor de las pruebas unitarias, pero YMMV. Por ejemplo, ¿con qué frecuencia ejecuta su conjunto de pruebas integrado? Mi experiencia con las pruebas integradas es que, tarde o temprano, se volverán tan lentas que no las ejecutará cada vez que realice un cambio y el tiempo entre la inserción y la detección de un error aumentará.

Además, un gran error que puede estar cometiendo es confiar en que

Find bug that may not be caught in integration test. e.g. masking/offsetting bugs.

no es importante. ¿Espera que sus usuarios encuentren los errores por usted? Confiar en las coberturas obtenidas de las pruebas integradas es peligroso en mi opinión, puede obtener fácilmente un alto porcentaje de cobertura, pero en realidad está probando muy poco.

Supongo que la referencia canónica contra las pruebas integradas son las publicaciones de JBrains:

http://www.jbrains.ca/permalink/integrated-tests-are-a-scam-part-1

en caso de que no los hayas leído ya.

Finalmente, IMO la retroalimentación que puede obtener de las pruebas unitarias para su diseño es invaluable. Juzgar un diseño por instinto y confiar en pruebas integradas también puede ser un error.

José Ricardo
fuente
Realmente no entiendo ese artículo. Por lo tanto, hay muchas rutas de código y las pruebas de integración no pueden abarcarlas todas ... ¿entonces? Lo mismo se aplica a las pruebas unitarias a menos que sus unidades sean tan triviales que no tengan sentido.
Casey
Es más como un argumento en contra de la fijación de la cobertura de código en absoluto que uno debería escribir un montón de pruebas unitarias y evitar las pruebas de integración.
Casey
1

Si alguna vez tiene que modificar o refactorizar su código, es esencial realizar pruebas unitarias. Las pruebas unitarias existen no solo para demostrar errores en el momento en que se escribe el código, sino para mostrar cuándo aparecen nuevos errores cuando se escribe más código.

Sí, es mucho mejor escribir primero las pruebas de integración y de unidad, pero es muy valioso tenerlas incluso si se escriben más tarde.

Matthew Flynn
fuente
3
No creo que hayas hecho el caso. Las pruebas de integración también revelarían errores en el código, y de hecho son capaces de detectar errores que las pruebas unitarias no detectarán.
Casey