¿Por qué las pruebas de unidad no se ven como malas?

88

Aparentemente, en algunas organizaciones, parte del proceso de lanzamiento del software es usar pruebas unitarias, pero en cualquier momento deben pasar todas las pruebas unitarias. Por ejemplo, podría haber alguna pantalla que muestre que todas las pruebas de unidad pasen en verde, lo que se supone que es bueno.

Personalmente, creo que no es así como debería ser por las siguientes razones:

  1. Promueve la idea de que el código debería ser perfecto y que no deberían existir errores, lo que en el mundo real es seguramente imposible para un programa de cualquier tamaño.

  2. Es un desincentivo pensar en pruebas de unidad que fallarán. O, sin duda, realice pruebas unitarias que sean difíciles de arreglar.

  3. Si en algún momento en el tiempo todas las pruebas de unidad pasan, entonces no hay un panorama general del estado del software en ningún momento. No hay una hoja de ruta / objetivo.

  4. Detiene la escritura de pruebas unitarias por adelantado, antes de la implementación.

Incluso sugeriría que incluso lanzar software con pruebas unitarias fallidas no es necesariamente malo. Al menos entonces sabes que algún aspecto del software tiene limitaciones.

¿Me estoy perdiendo algo aquí? ¿Por qué las organizaciones esperan que todas las pruebas unitarias pasen? ¿No es esto vivir en un mundo de sueños? ¿Y realmente no impide una comprensión real del código?

    
pregunta user619818 22.05.2018 - 12:32

17 respuestas

263

Esta pregunta contiene, en mi humilde opinión, varios conceptos erróneos, pero el principal en el que me gustaría centrarme es que no distingue entre ramas de desarrollo local, troncal, puesta en escena o ramas de lanzamiento.

En una rama de desarrollo local, es probable que se realicen algunas pruebas de unidad que fallan en casi cualquier momento. En el maletero, solo es aceptable hasta cierto punto, pero ya es un indicador sólido para arreglar las cosas lo antes posible. Tenga en cuenta que las pruebas unitarias que fallan en el tronco pueden perturbar al resto del equipo, ya que requieren que todos verifiquen si su último cambio fue el que causó la falla.

En una bifurcación de lanzamiento o de lanzamiento, las pruebas que fallan son "alerta roja", y muestran que algo se ha equivocado completamente con algunos cambios, cuando se fusionó desde el tronco hacia la bifurcación de lanzamiento.

  

Incluso sugeriría que incluso lanzar software con pruebas unitarias fallidas no es necesariamente malo.

La liberación de software con errores conocidos por debajo de una cierta gravedad no es necesariamente mala. Sin embargo, estos fallos conocidos no deberían causar una prueba de unidad fallida. De lo contrario, después de cada prueba de unidad, uno tendrá que mirar las 20 pruebas de unidad fallidas y verificar una por una si la falla fue aceptable o no. Esto se vuelve engorroso, propenso a errores y descarta una gran parte del aspecto de automatización de las pruebas unitarias.

Si realmente tiene pruebas para detectar errores conocidos y aceptables, use la función de deshabilitar / ignorar de su herramienta de prueba de unidad (para que no se ejecuten de forma predeterminada, solo a pedido). Además, agregue un ticket de baja prioridad a su rastreador de problemas, para que el problema no se olvide.

    
respondido por el Doc Brown 22.05.2018 - 13:48
226
  

... todas las pruebas de unidad pasan en verde, lo que se supone que es bueno.

Es es bueno. No "se supone que sea" al respecto.

  

Promueve la idea de que el código debería ser perfecto y que no deberían existir errores, lo que en el mundo real es seguramente imposible para un programa de cualquier tamaño.

No. Prueba que has probado el código tan bien como puedes hasta este punto. Es totalmente posible que sus pruebas no cubran todos los casos. Si es así, cualquier error eventualmente aparecerá en los informes de errores y escribirá pruebas [fallidas] para reproducir los problemas y luego arreglará la aplicación para que pasen las pruebas.

  

Es un desincentivo pensar en pruebas unitarias que fallarán.

Las pruebas negativas o que fallan ponen límites firmes a lo que su solicitud aceptará o no. La mayoría de los programas que conozco se opondrán a una "fecha" del 30 de febrero. Además, los desarrolladores, los tipos creativos que somos, no quieren romper "sus bebés". El enfoque resultante en los casos de "ruta feliz" lleva a aplicaciones frágiles que se rompen, a menudo.

Para comparar la mentalidad del desarrollador y el probador:

  • Un desarrollador se detiene tan pronto como el código hace lo que quiere.
  • Un probador se detiene cuando ya no puede hacer que el código se rompa.

Estas son perspectivas radicalmente diferentes y una que es difícil de conciliar para muchos Desarrolladores.

  

O, sin duda, realice pruebas unitarias que serían difíciles de arreglar.

No escribes pruebas para hacer el trabajo por ti mismo. Escribes pruebas para asegurarte de que tu código está haciendo lo que se supone que debe hacer y, lo que es más importante, continúa para hacer lo que se supone que debe hacer después de que hayas cambiado su Implementación interna.

  • La depuración "prueba" que el código hace lo que usted quiere que hoy .
  • Las pruebas "prueban" que el código aún hace lo que usted quiere que con el tiempo .
  

Si en algún momento se superan todas las pruebas de unidad, entonces no hay un panorama general del estado del software en ningún momento. No hay una hoja de ruta / objetivo.

La única prueba de "imagen" le proporciona una instantánea de que el código "funciona" en el momento en que se probó. Cómo evoluciona después de eso es una historia diferente.

  

Detiene la escritura de pruebas unitarias por adelantado, antes de la implementación.

Eso es exactamente lo que deberías estar haciendo. Escriba una prueba que falle (porque el método que está probando todavía no se ha implementado) luego escriba el código del método para que el método funcione y, por lo tanto, la prueba pase. Eso es más o menos el punto crucial del desarrollo dirigido por pruebas.

  

Incluso sugeriría que incluso lanzar software con pruebas unitarias fallidas no es necesariamente malo. Al menos entonces sabes que algún aspecto del software tiene limitaciones.

La liberación de código con pruebas rotas significa que parte de su funcionalidad ya no funciona como lo hacía antes. Eso puede ser un acto deliberado porque corrigió un error o mejoró una función (pero luego debería haber cambiado la prueba primero para que fallara, luego codificó la corrección / mejora, haciendo que la prueba funcione en el proceso). Más importante aún: todos somos humanos y cometemos errores. Si rompe el código, entonces debe romper las pruebas y esas pruebas rotas deben hacer que suenen las campanas de alarma.

  

¿No es esto vivir en un mundo de sueños?

En todo caso, es vivir en el Mundo Real , reconociendo que los Desarrolladores no son ni omniscientes ni inflables, que cometemos cometer errores y que necesitamos una seguridad net para atraparnos cuando hagamos el desastre!
Entrar en pruebas

  

¿Y realmente no impide una comprensión real del código?

Quizás. No necesariamente necesitas entender la implementación de algo para escribir la prueba para eso (eso es parte del punto de ellos). Las pruebas definen el comportamiento y los límites de la aplicación y garantizan que se mantengan igual a menos que se cambien deliberadamente.

    
respondido por el Phill W. 22.05.2018 - 13:08
31
  

¿Por qué las pruebas unitarias fallan como malas?

No son: el desarrollo guiado por pruebas se basa en la noción de pruebas fallidas. Pruebas de unidad que fallan para impulsar el desarrollo, pruebas de aceptación que fallan para impulsar una historia ...

Lo que te falta es context ; ¿Dónde pueden fallar las pruebas unitarias?

La respuesta habitual es que las pruebas unitarias solo pueden fallar en espacios limitados privados.

La noción básica es esta: en un entorno donde se comparten pruebas fallidas, se requiere un esfuerzo adicional para comprender si un cambio en el código de producción ha introducido un nuevo error. La diferencia entre cero y no cero es mucho más fácil de detectar y administrar que la diferencia entre N y no N.

Además, mantener limpio el código compartido significa que los desarrolladores pueden permanecer en la tarea. Cuando fusiono su código, no necesito cambiar los contextos del problema que se me está pagando para resolver y calibrar mi comprensión de cuántas pruebas deberían estar fallando. Si el código compartido pasa todas las pruebas, cualquier falla que aparezca cuando fusiono mis cambios debe debe ser parte de la interacción entre mi código y la línea de base limpia existente.

Del mismo modo, durante el embarque, un nuevo desarrollador puede ser productivo más rápidamente, ya que no necesitan dedicar tiempo a descubrir qué pruebas fallidas son "aceptables".

Para ser más precisos: la disciplina es que las pruebas que se ejecutan durante la compilación deben pasar.

Hay, lo mejor que puedo decir, nada mal al tener pruebas fallidas que están deshabilitadas .

Por ejemplo, en un entorno de "integración continua", compartirás código en una cadencia alta. Integrar a menudo no significa necesariamente que sus cambios deban estar listos para su lanzamiento. Hay una variedad de técnicas de implementación oscura que impiden que el tráfico se libere en secciones del código hasta que estén listos.

Esas mismas técnicas se pueden usar para deshabilitar las pruebas fallidas también.

Uno de los ejercicios que realicé en un lanzamiento puntual fue el desarrollo de un producto con muchas pruebas fallidas. La respuesta que obtuvimos fue simplemente revisar el conjunto de aplicaciones, deshabilitar las pruebas fallidas y documentar cada una. Eso nos permitió llegar rápidamente a un punto en el que se aprobaron todas las pruebas habilitadas, y la gerencia / donante de objetivos / dueño de oro pudo ver qué intercambios habíamos realizado para llegar a ese punto y tomar decisiones informadas sobre la limpieza frente al nuevo trabajo.

En resumen: existen otras técnicas para rastrear trabajo no realizado que dejar un montón de pruebas fallidas en la suite en ejecución.

    
respondido por el VoiceOfUnreason 22.05.2018 - 14:37
25

Hay muchas respuestas geniales, pero me gustaría agregar otro ángulo que creo que aún no está bien cubierto: cuál es exactamente el punto de las pruebas.

Las pruebas unitarias no están ahí para verificar que su código esté libre de errores.

Creo que este es el principal error. Si este fuera su rol, de hecho esperaría tener pruebas fallidas en todo el lugar. Pero en cambio,

Las pruebas unitarias comprueban que su código hace lo que usted cree que hace.

En casos extremos, puede incluir la comprobación de que los errores conocidos no se han solucionado. El punto es tener control sobre su base de código y evitar cambios accidentales. Cuando realiza un cambio, está bien y realmente se espera que rompa algunas pruebas: está cambiando el comportamiento del código. La prueba que acaba de fallar ahora es un buen rastro de lo que cambió. Verifique que todas las roturas se ajusten a lo que desea de su cambio. Si es así, simplemente actualice las pruebas y continúe. Si no es así, bueno, ¡su nuevo código es definitivamente defectuoso, vuelva atrás y repárelo antes de enviarlo!

Ahora, todo lo anterior funciona solo si todas las pruebas son de color verde, dando resultados positivos: así es exactamente cómo funciona el código. Las pruebas rojas no tienen esa propiedad. "Esto es lo que este código no hace" rara vez es una información útil.

Las pruebas de aceptación pueden ser lo que está buscando.

Hay pruebas de aceptación. Puede escribir un conjunto de pruebas que deben cumplirse para llamar al siguiente hito. Estos están bien para ser rojos, porque para eso fueron diseñados. Pero son cosas muy diferentes de las pruebas unitarias y ni pueden ni deben reemplazarlos.

    
respondido por el Frax 22.05.2018 - 18:17
24

Lo veo como el software equivalente de síndrome de ventana rota .

Las pruebas de trabajo me dicen que el código es de una calidad determinada y que a los propietarios del código les importa.

En cuanto a cuándo debería preocuparse por la calidad, eso depende más bien del código fuente / sucursal en el que esté trabajando. El código de desarrollo puede muy bien tener pruebas rotas que indiquen trabajo en progreso (¡con suerte!).

Las pruebas rotas en una sucursal / repositorio de un sistema en vivo deben activar de inmediato el timbre de alarma. Si se permite que los exámenes rotos continúen fallando o si están marcados permanentemente como "ignorar", espere que su número aumente con el tiempo. Si no se revisan con regularidad, se habrá establecido el precedente de que está bien que se dejen las pruebas rotas.

Las

pruebas rotas se ven de manera tan peyorativa en muchas tiendas como para tener una restricción sobre si el código roto puede incluso confirmarse .

    
respondido por el Robbie Dee 22.05.2018 - 14:54
11

Aquí está la falacia lógica subyacente:

  

Si es bueno cuando todas las pruebas pasan, entonces debe ser malo si las pruebas fallan.

Con las pruebas unitarias, ES está bien cuando pasan todas las pruebas. Es TAMBIÉN BIEN cuando falla una prueba. Los dos no necesitan estar en oposición.

Una prueba fallida es un problema que detectaron sus herramientas antes de que llegara a un usuario. Es una oportunidad para corregir un error antes de que se publique. Y eso es algo bueno.

    
respondido por el Joel Coehoorn 22.05.2018 - 19:47
9

La respuesta de Phill W es genial. No puedo reemplazarlo.

Sin embargo, quiero centrarme en otra parte que puede haber sido parte de la confusión.

  

Al parecer, en algunas organizaciones, parte del proceso de lanzamiento del software es utilizar pruebas unitarias, pero en cualquier momento todas las pruebas unitarias deben pasar

"en cualquier momento" está exagerando su caso. Lo importante es que las pruebas unitarias pasan después de que se haya implementado un cierto cambio, antes que empiece a implementar otro cambio.
Esta es la forma en que se realiza un seguimiento de qué cambio causó un error. Si las pruebas de unidad empezaron a fallar después de implementar el cambio 25 pero antes de implementar el cambio 26, entonces se sabe que el cambio 25 causó el error.

Durante la implementación de un cambio, por supuesto, las pruebas unitarias podrían fallar; Tat depende mucho de qué tan grande es el cambio. Si estoy volviendo a desarrollar una función principal, que es más que un pequeño ajuste, es probable que rompa las pruebas por un tiempo hasta que termine de implementar mi nueva versión de la lógica.

Esto puede crear conflictos en cuanto a las reglas del equipo. De hecho, me encontré con esto hace unas semanas:

  • Cada commit / push provoca una compilación. La compilación nunca debe fallar (si lo hace o si falla alguna prueba, se culpa al desarrollador que cometió el compromiso).
  • Se espera que todos los desarrolladores presionen sus cambios (incluso si están incompletos) al final del día, por lo que los líderes del equipo pueden revisar el código por la mañana.

Cualquiera de las reglas estaría bien. Pero las reglas ambas no pueden funcionar juntas. Si me asignan un cambio importante que demore varios días en completarse, no podré cumplir con ambas reglas al mismo tiempo. A menos que comente mis cambios todos los días y solo los cometa sin comentarios después de que se haya hecho todo; que es solo un trabajo sin sentido.

En este escenario, el problema aquí no es que las pruebas unitarias no tengan ningún propósito; es que la empresa tiene expectativas poco realistas . Su conjunto de reglas arbitrarias no cubre todos los casos, y el incumplimiento de las reglas se considera ciegamente como una falla del desarrollador en lugar de una falla de la regla (que es, en mi caso).

    
respondido por el Flater 22.05.2018 - 15:57
6

Si no arregla todas las pruebas unitarias, puede ingresar rápidamente al estado en el que nadie arregla las pruebas fallidas.

  1. Es incorrecto, ya que pasar las pruebas unitarias no muestra que el código sea perfecto

  2. Es un desincentivo crear un código que también sería difícil de probar, lo que es bueno desde el punto de vista del diseño

  3. La cobertura del código puede ayudar allí (aunque no es una panacea). Además, las pruebas unitarias son solo uno de los aspectos de las pruebas: también desea pruebas de integración / aceptación.

respondido por el jk. 22.05.2018 - 12:35
6

Para agregar algunos puntos a las respuestas ya buenas ...

  

pero en cualquier momento, todas las pruebas de unidad deben pasar

Esto muestra una falta de comprensión de un proceso de lanzamiento. Un fallo de prueba puede indicar una característica planificada en TDD que aún no se ha implementado; o puede indicar un problema conocido que tiene una solución planificada para una versión futura; o simplemente puede ser algo en el que la gerencia haya decidido que esto no es lo suficientemente importante como para solucionarlo porque es poco probable que los clientes lo noten. La clave que comparten todos estos es que la administración ha emitido un juicio acerca de la falla.

  

Promueve la idea de que el código debería ser perfecto y que no deberían existir errores, lo que en el mundo real es seguramente imposible para un programa de cualquier tamaño.

Otras respuestas han cubierto los límites de las pruebas.

No entiendo por qué crees que eliminar errores es un inconveniente. Si no desea entregar el código que ha marcado (lo mejor que pueda) hace lo que se supone que debe hacer, ¿por qué está trabajando en software?

  

Si en algún momento se superan todas las pruebas de unidad, entonces no hay un panorama general del estado del software en ningún momento. No hay una hoja de ruta / objetivo.

¿Por qué debe haber una hoja de ruta?

Las pruebas de unidad inicialmente comprueban que la funcionalidad funciona, pero luego (como pruebas de regresión) verifican que no se haya roto nada inadvertidamente. Para todas las funciones con pruebas de unidad existentes, no hay una hoja de ruta . Se sabe que todas las características funcionan (dentro de los límites de las pruebas). Si ese código está terminado, no tiene una hoja de ruta porque no hay necesidad de trabajar más en él.

Como ingenieros profesionales, debemos evitar la trampa del chapado en oro. Los aficionados pueden darse el lujo de perder el tiempo jugando con los bordes con algo que funciona. Como profesionales, tenemos que entregar un producto. Eso significa que conseguimos que algo funcione, verificamos que funciona y pasamos al siguiente trabajo.

    
respondido por el Graham 22.05.2018 - 16:34
6
  

Promueve la idea de que el código debería ser perfecto y que no deberían existir errores, lo que en el mundo real es seguramente imposible para un programa de cualquier tamaño.

No es cierto. ¿Por qué crees que es imposible? Aquí ejemplo para el programa que funciona:

public class MyProgram {
  public boolean alwaysTrue() {
    return true;
  }

  @Test
  public void testAlwaysTrue() {
    assert(alwaysTrue() == true);
  }
}
  

Es un desincentivo pensar en pruebas unitarias que fallarán. O, sin duda, realizar pruebas unitarias que serían difíciles de arreglar.

En ese caso, puede que no sea una prueba unitaria, sino una prueba de integración si es complicada

  

Si en algún momento se superan todas las pruebas de unidad, entonces no hay un panorama general del estado del software en ningún momento. No hay una hoja de ruta / objetivo.

cierto, se llama unidad prueba por una razón, verifica una pequeña unidad de código.

  

Detiene la escritura de pruebas unitarias por adelantado, antes de la implementación.

Los desarrolladores detendrán la escritura de cualquier prueba si no comprenden sus beneficios por su naturaleza (a menos que provengan de control de calidad)

    
respondido por el user7294900 22.05.2018 - 12:44
4
  

Promueve la idea de que el código debería ser perfecto y que no deberían existir errores

Definitivamente no. Promueve la idea de que tus pruebas no deben fallar, nada más y nada menos. Asumir que tener pruebas (incluso muchas de ellas) dice algo sobre "perfecto" o "sin errores" es una falacia. Decidir qué tan superficial o profunda deberían ser sus pruebas es una parte importante de escribir buenas pruebas, y la razón por la que tenemos categorías de pruebas separadas (pruebas de "unidad", pruebas de integración, "escenarios" en el sentido del pepino, etc.).

  

Es un desincentivo pensar en pruebas unitarias que fallarán. O, sin duda, realizar pruebas unitarias que serían difíciles de arreglar.

En el desarrollo guiado por pruebas, es obligatorio que todas las pruebas unitarias falle primero, antes de comenzar a codificar. Se llama "ciclo rojo-verde" (o "ciclo rojo-verde-refactor") por esta misma razón.

  • Sin que la prueba falle, no sabe si la prueba realmente ha probado el código. Los dos podrían no estar relacionados en absoluto.
  • Al cambiar el código a exactamente hacer que la prueba cambie de rojo a verde, nada más y nada menos, puede estar bastante seguro de que su código hace lo que se supone que debe hacer, y no una mucho más (que nunca podría necesitar).
  

Si en algún momento se superan todas las pruebas de unidad, entonces no hay un panorama general del estado del software en ningún momento. No hay una hoja de ruta / objetivo.

Las pruebas son más bien un micro-objetivo. En el desarrollo guiado por pruebas, el programador escribirá una prueba (singular) primero, y luego tendrá un objetivo claro para implementar algún código; luego la siguiente prueba, y así sucesivamente.

La función de las pruebas no debe estar completa antes de escribir el código.

Cuando se realiza correctamente, en un idioma y con una biblioteca de pruebas que se adapta bien a este enfoque, esto puede acelerar enormemente el desarrollo, ya que los mensajes de error (excepciones / stacktraces) pueden dirigir directamente al desarrollador hacia donde necesita. para realizar el trabajo siguiente.

  

Detiene la escritura de pruebas unitarias por adelantado, antes de la implementación.

No veo cómo esta declaración sería verdadera. Lo ideal es que las pruebas de escritura sean una parte de la implementación.

  

¿Me estoy perdiendo algo aquí? ¿Por qué las organizaciones esperan que todas las pruebas unitarias pasen?

Porque las organizaciones esperan que las pruebas tengan relevancia para el código. Escribir pruebas que sean exitosas significa que usted ha documentado alguna parte de su aplicación y ha probado que la aplicación hace lo que dice (la prueba). Nada más y nada menos.

Además, una parte muy importante de las pruebas es la "regresión". Desea poder desarrollar o refactorizar el nuevo código con confianza. Tener una gran cantidad de pruebas verdes te permite hacer eso.

Esto va desde el nivel organizativo hasta el psicológico. Un desarrollador que sabe que sus errores probablemente serán atrapados por las pruebas será mucho más libre para encontrar soluciones inteligentes y audaces para los problemas que necesita resolver. Por otro lado, un desarrollador que no tiene pruebas, después de algún tiempo, se quedará paralizado (debido al miedo) porque nunca sabe si un cambio que hace rompe el resto de la aplicación.

  

¿No es esto vivir en un mundo de sueños?

No. Trabajar con una aplicación basada en pruebas es pura alegría, a menos que simplemente no te guste el concepto por cualquier motivo ("más esfuerzo", etc., etc.) que podamos analizar en otra pregunta.

  

¿Y realmente no impide una comprensión real del código?

Absolutamente no, ¿por qué?

Encontrará muchos proyectos grandes de código abierto (para los que la gestión de la "comprensión" y los conocimientos técnicos sobre el código es un tema muy importante) que utilizan las pruebas como la documentación principal del software, aparte de Al ser pruebas, también se proporcionan ejemplos reales, funcionales y sintácticamente correctos para los usuarios o desarrolladores de la aplicación / biblioteca. Esto a menudo funciona espléndidamente.

Obviamente, escribir malas pruebas es malo. Pero eso no tiene nada que ver con la función de las pruebas en sí.

    
respondido por el AnoE 23.05.2018 - 11:14
3

(De mis comentarios originales)

Hay una diferencia entre la funcionalidad requerida y los objetivos futuros. Las pruebas son para la funcionalidad requerida: son precisas, formales, ejecutables y si fallan, el software no funciona. Es posible que las metas futuras no sean precisas o formales, y mucho menos ejecutables, por lo que es mejor dejarlas en un lenguaje natural como en el seguimiento de errores / problemas, documentación, comentarios, etc.

Como ejercicio, intente reemplazar la frase "prueba de unidad" en su pregunta con "error de compilación" (o "error de sintaxis", si no hay compilador). Es obvio que una versión no debería tener errores de compilación, ya que sería inutilizable; sin embargo, los errores de compilación y los errores de sintaxis son el estado normal de las cosas en la máquina de un desarrollador cuando escriben código. Los errores solo desaparecen cuando han terminado; y eso es exactamente cuando el código debe ser empujado. Ahora reemplace "error del compilador" en este párrafo con "prueba de unidad" :)

    
respondido por el Warbo 23.05.2018 - 19:25
2

El propósito de las pruebas automatizadas es informarle cuándo ha roto algo lo antes posible . El flujo de trabajo se ve un poco así:

  1. Hacer un cambio
  2. Construye y prueba tu cambio (idealmente automáticamente)
  3. Si las pruebas fallan, significa que rompió algo que funcionó anteriormente
  4. si las pruebas pasan, debe confiar en que su cambio no introdujo nuevas regresiones (según la cobertura de la prueba)

Si sus pruebas ya estaban fallando, entonces el paso # 3 no funciona con la misma eficacia: las pruebas fallarán, pero no sabe si eso significa que rompió algo o no sin investigar. Tal vez podría contar el número de pruebas fallidas, pero luego un cambio podría corregir un error y romper otro, o una prueba podría comenzar a fallar por una razón diferente. Esto significa que debe esperar un poco de tiempo antes de saber si se ha roto algo, ya sea hasta que se hayan solucionado todos los problemas o hasta que se haya investigado cada prueba que falla.

La capacidad de las pruebas unitarias para encontrar errores recién introducidos lo antes posible es lo más valioso de las pruebas automatizadas: cuanto más se pierde el defecto, más costoso es solucionarlo.

  

Promueve la idea de que el código debería ser perfecto y que no deberían existir errores.
  Es un desincentivo pensar en las pruebas unitarias que fallarán

Las pruebas de las cosas que no funcionan no le dicen nada: escriba pruebas de unidad para las cosas que funcionan o que está a punto de arreglar. No significa que su software esté libre de defectos, significa que ninguno de los defectos para los que realizó pruebas de unidad previamente ha vuelto a aparecer.

  

Detiene las pruebas de unidad de escritura por adelantado

Si te funciona, entonces escribe las pruebas por adelantado, simplemente no las ingreses en tu maestro / troncal hasta que pasen.

  

Si en algún momento se superan todas las pruebas de unidad, entonces no hay un panorama general del estado del software en ningún momento. No hay una hoja de ruta / objetivo.

Las pruebas unitarias no son para establecer una hoja de ruta / objetivo, ¿quizás usar un backlog para eso? Si todas sus pruebas pasan, entonces el "panorama general" es que su software no está roto (si su cobertura de prueba es buena). ¡Bien hecho!

    
respondido por el Justin 23.05.2018 - 22:30
2

Las respuestas existentes son ciertamente buenas, pero no he visto a nadie abordar este error fundacional en la pregunta:

  

en cualquier momento, todas las pruebas de unidad deben pasar

No. Con toda seguridad, esto no será cierto. Mientras estoy desarrollando software, NCrunch suele ser marrón (falla de compilación) o rojo (prueba fallida).

Donde NCrunch debe ser verde (todas las pruebas que pasan) es cuando estoy listo para enviar un compromiso al servidor de control de origen, porque en ese momento otros pueden depender de mi código.

Esto también se relaciona con el tema de la creación de nuevas pruebas: las pruebas deben afirmar la lógica y el comportamiento del código. Condiciones de frontera, condiciones de falla, etc. Cuando escribo nuevas pruebas, trato de identificar estos "puntos calientes" en el código.

Las pruebas unitarias documentan cómo espero que se llame mi código: condiciones previas, resultados esperados, etc.

Si se rompe una prueba después de un cambio, debo decidir si el código o la prueba son erróneos.

Como nota al margen, las pruebas unitarias a veces van de la mano con el desarrollo dirigido por pruebas. Uno de los principios de TDD es que las pruebas interrumpidas son sus guías. Cuando falla una prueba, debe corregir el código para que la prueba pase. Aquí hay un ejemplo concreto de principios de esta semana:

Fondo : escribí y ahora admito una biblioteca utilizada por nuestros desarrolladores que se usa para validar las consultas de Oracle. Teníamos pruebas que afirmaban que la consulta coincidía con algún valor esperado, lo que hacía que el caso fuera importante (no está en Oracle) y aprobaba alegremente las consultas no válidas siempre que coincidieran completamente con el valor esperado.

En su lugar, mi biblioteca analiza la consulta usando Antlr y una sintaxis de Oracle 12c, y luego ajusta varias aserciones en el propio árbol de sintaxis. Cosas como, es válido (no se generaron errores de análisis), todos los parámetros están satisfechos por la colección de parámetros, todas las columnas esperadas leídas por el lector de datos están presentes en la consulta, etc. Todos estos son elementos que se han deslizado hasta Producción en distintos momentos.

Uno de mis colegas ingenieros me envió una consulta el lunes que había fallado (o más bien, había tenido éxito cuando debería haber fallado) durante el fin de semana. Mi biblioteca dijo que la sintaxis estaba bien, pero explotó cuando el servidor intentó ejecutarlo. Y cuando miró la consulta, fue obvio por qué:

UPDATE my_table(
SET column_1 = 'MyValue'
WHERE id_column = 123;

Cargué el proyecto y agregué una prueba de unidad que afirmaba que esta consulta no debería ser válida. Obviamente, la prueba falló.

A continuación, depuré la prueba fallida, revisé el código donde esperaba que lanzara la excepción y descubrí que Antlr estaba provocando un error en el paren abierto, pero no de una manera. El código anterior estaba esperando. Modifiqué el código, verifiqué que la prueba ahora era verde (aprobable) y que ninguna otra persona había roto el proceso, cometido y presionado.

Esto llevó unos 20 minutos, y en el proceso mejoré significativamente la biblioteca porque ahora admitía toda una gama de errores que previamente había ignorado. Si no tuviera pruebas de unidad para la biblioteca, la investigación y la solución del problema podrían haber llevado horas.

    
respondido por el GalacticCowboy 24.05.2018 - 16:20
0

Un punto que no creo que surja de las respuestas anteriores es que hay una diferencia entre las pruebas internas y las pruebas externas (y creo que muchos proyectos no son lo suficientemente cuidadosos para distinguirlos). Una prueba interna prueba que algún componente interno está funcionando como debería; una prueba externa muestra que el sistema en su conjunto está funcionando como debería. Es bastante posible, por supuesto, tener fallas en los componentes que no resulten en una falla del sistema (quizás haya una característica del componente que el sistema no usa, o tal vez el sistema se recupera de una falla de la componente). Una falla de un componente que no resulte en una falla del sistema no debería impedirle la liberación.

He visto proyectos paralizados por tener demasiadas pruebas internas de componentes. Cada vez que intenta implementar una mejora de rendimiento, rompe docenas de pruebas, porque está cambiando el comportamiento de los componentes sin cambiar realmente el comportamiento del sistema visible desde el exterior. Esto conduce a una falta de agilidad en el proyecto en su conjunto. Creo que la inversión en pruebas de sistemas externos generalmente tiene una mejor recompensa que la inversión en pruebas de componentes internos, especialmente cuando se habla de componentes de muy bajo nivel.

Cuando sugieres que las pruebas de unidad que fallan realmente no importan, me pregunto si esto es lo que tienes en mente. Tal vez debería evaluar el valor de las pruebas unitarias y deshacerse de aquellas que causan más problemas de los que valen, mientras se enfoca más en las pruebas que verifican el comportamiento de la aplicación visible externamente.

    
respondido por el Michael Kay 24.05.2018 - 15:43
0

"pero en cualquier momento, todas las pruebas de unidad deben pasar"

Si esa es la actitud en su empresa, eso es un problema. En un momento CIERTO, es decir, cuando declaramos que el código está listo para pasar al siguiente entorno, todas las pruebas de unidad deben pasar. Pero durante el desarrollo, deberíamos esperar rutinariamente que muchas pruebas unitarias fallen.

Ninguna persona razonable espera que un programador haga su trabajo perfecto en el primer intento. Lo que razonablemente esperamos es que siga trabajando en ello hasta que no haya problemas conocidos.

"Es un desincentivo pensar en las pruebas unitarias que van a fallar. O, ciertamente, crear pruebas unitarias que serían difíciles de arreglar". Si alguien en su organización piensa que no debería mencionar una posible prueba porque podría fallar y causarle más trabajo para solucionarlo, esa persona no está calificada para su trabajo. Esta es una actitud desastrosa. ¿Querría un médico que diga: "Cuando me esté practicando una cirugía, deliberadamente no compruebo si los puntos son correctos, porque si veo que no, tendré que regresar y volver a hacerlos y eso ralentizará terminando la operación "?

Si el equipo es hostil a los programadores que identifican los errores antes de que el código pase a producción, tiene un problema real con la actitud de ese equipo. Si la administración castiga a los programadores que identifican errores que retrasan la entrega, lo más probable es que su empresa se dirija a la quiebra.

Sí, es cierto que a veces las personas racionales dicen: "Nos estamos acercando a la fecha límite, este es un problema trivial y no vale la pena dedicar los recursos en este momento que se necesitarían para solucionarlo". Pero no puedes tomar esa decisión racionalmente si no lo sabes. Examinar con frialdad una lista de errores y asignar prioridades y horarios para corregirlos es racional. Hacerse deliberadamente ignorante de los problemas para no tener que tomar esta decisión es una tontería. ¿Crees que el cliente no lo averiguará solo porque no querías saberlo?

    
respondido por el Jay 28.05.2018 - 01:17
-7

Este es un ejemplo específico de sesgo de confirmación , donde la gente tiende a buscar información que confirme sus creencias existentes.

Un ejemplo famoso de esto ocurre, está en el juego 2,4,6.

  • Tengo una regla en mi cabeza de que cualquier serie de tres números pasará o fallará,
  • 2,4,6 es un pase
  • puede hacer una lista de conjuntos de tres números, y le diré si pasan o no.

La mayoría de las personas eligen una regla, dicen "la brecha entre el primer y el segundo número es la misma que la brecha entre el segundo y el tercero".

Probarán algunos números:

  • 4, 8, 12? Pase
  • 20, 40, 60? Pase
  • 2, 1004, 2006? Pase

Dicen: "Sí, cada observación confirma mi hipótesis, debe ser cierta". Y anuncie su regla a la persona que da el enigma.

Pero nunca recibieron un solo 'error' en ningún conjunto de tres números. La regla podría haber sido "los tres números deben ser números" para toda la información que realmente tienen.

La regla es en realidad solo que los números están en orden ascendente. Por lo general, las personas solo obtienen este acertijo correctamente si prueban el fracaso. La mayoría de las personas se equivocan al elegir una regla más específica y solo a los números de prueba que cumplen con esta regla específica.

En cuanto a por qué las personas se inclinan por el sesgo de confirmación, y pueden ver que las pruebas unitarias fallan como evidencia de un problema, hay muchos psicólogos que pueden explicar el sesgo de confirmación mejor que yo, básicamente se trata de personas que no les gusta estar equivocadas y que tienen dificultades. para intentar genuinamente probar que están equivocados.

    
respondido por el Scott 23.05.2018 - 06:17

Lea otras preguntas en las etiquetas