2010-01-13 7 views
11

Mantener las pruebas unitarias es difícil. Estoy seguro de que todos hemos experimentado un momento en el que un cambio aparentemente pequeño en el sistema sometido a prueba provocó la falla de docenas de pruebas unitarias. A veces, estas fallas revelan errores en el SUT, pero a menudo las pruebas están desactualizadas y ya no reflejan el comportamiento correcto del SUT. En estos casos, es necesario corregir las pruebas rotas.Evolución del programa y pruebas rotas

¿Ha encontrado esta situación? ¿Pasa a menudo? ¿Qué cambio introdujo y cómo se manifestaron las fallas? ¿Arreglaste las pruebas rotas o simplemente las borraste? Si el primero, ¿cómo? Si esto último, ¿por qué? ¿De qué manera el miedo a las fallas afecta tu deseo de escribir pruebas?

También me gustaría encontrar ejemplos específicos de pruebas rotas. ¿Conoces alguna aplicación de código abierto que haya evolucionado de forma que haya fallado la prueba?

Respuesta

6

Mantener las pruebas unitarias es difícil.

Lo suficientemente cierto. La coevolución del código de producción y el código de prueba juntos es difícil. Ambos tipos de similitudes de compartición de código (por ejemplo, convención de nomenclatura), pero aún difieren en naturaleza. Por ejemplo, el DRY puede ser violado en el código de prueba si es necesario; la duplicación de código se encontraría fácilmente ya que la prueba se rompería en ambos lugares. La tensión entre el código de prueba y el resultado de producción a veces da lugar a un intercambio de diseño específico (por ejemplo, inyección de dependencia) para facilitar la capacidad de prueba. Una vez más, estas tensiones son relativamente nuevas, y la relación entre el diseño en el código de producción y el esfuerzo en el mantenimiento no se entiende bien.El artículo "On the interplay between software testing and evolution" es excelente (no pude encontrarlo en PDF, pero no lo busqué en Google durante mucho tiempo).

estoy seguro de que todos hemos experimentado un momento en que un pequeño cambio aparentemente al sistema bajo prueba causó decenas de pruebas unitarias fallen. A veces estas fallas revelan los errores en el SUT, pero a menudo las pruebas son obsoletas y ya no reflejan el comportamiento correcto del SUT de . En estos casos , es necesario corregir las pruebas rotas .

localización de defectos - la capacidad de un conjunto de pruebas para localizar defectos precisamente - También se entiende sólo parcialmente. No están claras cuáles son las mejores estrategias para diseñar conjuntos de pruebas que den lugar a una localización de defectos elevada. La mayoría de las pruebas tienen cierta superposición entre ellas, lo que causa una baja localización de defectos. Ordenar pruebas para que dependan entre sí mejora este aspecto, pero al mismo tiempo va en contra del principio de tener pruebas aisladas. Vemos una conciencia cada vez mayor de tales tensiones, pero no hay una solución definitiva para abordar estos problemas. Aquí hay un artículo sobre exploiting dependencies between tests.

El problema de pruebas obsoletas o irrelevantes (aquellos que no cubren nada al final) también está aumentando la conciencia. La cobertura de la prueba no es suficiente y la suite de pruebas de alta calidad requiere experiencia o, al menos, algo de educación. Consulte este artículo sobre the 100% coverage myth.

¿Cómo afecta el miedo a las fallas su deseo de escribir pruebas?

usted tiene que encontrar un equilibrio entre (1) tiempo inicial invertido en banco de pruebas (2) el esfuerzo en mantenimiento y (3) la eficacia de la serie de pruebas. Escribo principalmente lo que llamo "pruebas de punto de inflexión" y aquí my view sobre el tema.

+0

Información excelente y citas. Exactamente el tipo de respuesta que estoy buscando. –

1

Personalmente, no creo que sea evitable. Puede minimizar los efectos a través del aislamiento del efecto, pero a veces puede ser bastante difícil. Los simulacros pueden ayudar, pero incluso a veces puede ser difícil trabajar con ellos. Sin embargo, si el comportamiento cambia y el cambio de comportamiento fue intencional y usted tiene pruebas Y que dependen del comportamiento, entonces tiene sentido que tenga que cambiar todas las expectativas Y. He descubierto que al hacer un poco de OOP, o simplemente con el diseño adecuado de la suite, a veces se puede ahorrar con la ventaja de volver a usar el código. Nunca le temo a las pruebas fallidas en este sentido, si el comportamiento necesita cambiar (y has pensado en esa necesidad, la necesidad es real y la necesidad no es el capricho de tu gerente que solía escribir COBOL en el buen 'days :-) entonces es solo parte de la evolución de la base de códigos y se debe considerar parte del trabajo a realizar. Si el reajuste del conjunto de pruebas lleva mucho tiempo, puede excluir las pruebas de su compilación y volver a incluirlas una a una, pero las pruebas que aún prueban un comportamiento esperado no se deben eliminar sino volver a factorizar. No permitamos que el banco de pruebas se erosione para obtener una nueva característica, si es que puede evitarse.

2

He observado, y ciertamente he leído en alguna parte, here o here, que las pruebas unitarias que prueban la implementación son más frágiles que las pruebas que prueban el comportamiento del código. O bien, las pruebas de unidad de caja blanca son más frágiles que las pruebas de unidad de caja negra. Por ejemplo, una prueba de una clase que almacena cosas se asoma directamente a los miembros del objeto de datos para verificar si las cosas están almacenadas, se romperá cuando la implementación de almacenamiento cambie.

+0

tiene eso al revés. Las pruebas de caja negra son más frágiles. lo describiste correctamente, pero transpuso los nombres, creo. – tster

+0

sí, se perdió eso. Lo arreglé, gracias. – philant

6

¿No es el objetivo de las pruebas unitarias informarle cuándo ha roto el código inesperadamente? Nunca eliminaría una prueba fallida a menos que fuera un código de ejercicio que fuera eliminado de mi sistema; debe considerar la creación y mantenimiento de pruebas como una parte integral de la escritura de su software, tan importante como el código entregado.

6

¿Cómo afecta el miedo a las fallas su deseo de escribir pruebas?

El miedo al fracaso es lo que impulsa mi deseo de escribir pruebas. Un banco de pruebas me da retroalimentación inmediata sobre si mi último cambio rompió algo y qué se rompió. El miedo es cambiar tu código, y no tienes idea de si las cosas funcionan o no.

3

estoy seguro de que todos hemos experimentado un momento en que un cambio aparentemente pequeño al sistema bajo prueba causó decenas de pruebas de unidad a fallar.

Aquí está su problema. El problema no es mantener las pruebas, el problema es que tienes una base de código frágil.Si un cambio provoca docenas de fallas, o bien tiene una base de código con muchos acoplamientos frágiles, o un conjunto de pruebas con muchas pruebas de pseudointegración que están probando demasiado.

Si un cambio está rompiendo docenas de pruebas, entonces probablemente necesite tomar un poco de tiempo para refactorizar las secciones fuertemente acopladas de su código O necesita romper sus pruebas y eliminar las condiciones de prueba duplicadas.

1

El problema que describe es algo que se aborda mejor al inicio del proyecto. Desde el momento en que comienzas a escribir tus pruebas unitarias (preferiblemente estilo TDD), debes estar constantemente consciente de la forma en que se desarrolla y evoluciona.
Aquí no hay ningún truco de magia, tienes que pensar mucho y darte cuenta cuando estás creando un lío enredado que de hecho hará más difícil mantener las pruebas. Por lo general, si las pruebas están tan enredadas, implica que parte del código de producción también podría usar alguna refactorización.

Básicamente, refactore constantemente para asegurarse de que los cambios estén localizados, y que no tenga que cambiar 200 casos de prueba simplemente porque decidió hacer un cambio simple. Uno diría que su código debe ser lo suficientemente granular como para permitir pruebas fáciles (no es necesario insertar diez objetos antes de llamar al código y probarlo), lo que generalmente hará que sea más fácil de mantener en unos pocos meses.

Todo el propósito de sus pruebas es para darle confianza. Más que eso, te permiten ser un poco estúpido. Si tienes suficientes pruebas de las que estás seguro, no tienes que pensar mucho antes de quitar algunas líneas de código que seguramente no usas. ¡Elimínalos y ejecuta las pruebas!
Porque creo que esta es una de las principales fortalezas de las pruebas unitarias, haría todo lo posible para evitar que el banco de pruebas sea algo que "temo". Si los cambios simples rompen las pruebas en lugares que nunca se esperarían, generalmente significa que necesita aprender más sobre su base de códigos, y probablemente haga algunos cambios para arreglar las cosas.

Hay muy pocos casos en que eliminé un caso de prueba el código probado que no se eliminó. Significa que incluso después de cavar muy profundo (volviendo al sistema de control de versiones) no puedo entender por qué la prueba está allí, o no estoy de acuerdo con ella. Pero mi primera forma de verlo es "maldición, me falta algo". Así de seguro debería estar uno con su suite, y es por eso que vale la pena el esfuerzo.

0

Si muchas de sus pruebas se interrumpen cuando se realiza un pequeño cambio en el software, entonces sus pruebas no se escriben con mucha solidez. Es importante escribir las pruebas para verificar el comportamiento del código, en lugar de la implementación. También debe asegurarse de que cada prueba sea lo más independiente posible.

En muchos casos, los cambios necesarios para hacer que el código sea más fácil de probar tendrán el efecto secundario de mejorar la calidad del código, ayudando a definir la interfaz entre los componentes, por ejemplo.

0

Mi respuesta a esto para algunos programas en los que estuve trabajando hace varios años fue preparar una serie de pruebas y las respuestas correctas para esas pruebas en el momento de la ejecución. Como los cambios en el software podrían cambiar la salida a otra salida correcta (alternativa), instituí un sistema de copia de seguridad de salida de prueba. Utilizando este sistema, pude rastrear los cambios en la salida de prueba y detectar errores involuntarios y rastrearlos cuando ocurrieron utilizando un programa de diferencias aplicado entre la salida actual y una de las salidas anteriores.
Mis pruebas se diseñaron para pasar por todos los ciclos principales del programa con diferentes opciones configuradas.
Esto fue antes de Windows-NT, por lo que todo se hizo con los archivos por lotes de DOS y las utilidades de DOS.
También escribí un mejorador de archivos por lotes que me permitió ejecutar los programas de forma similar a como lo hace UNIX y funciona xargs.

0

Este problema se conoce como fragilidad de prueba de unidad. La mayoría de las veces es causada por el acoplamiento entre sus pruebas y la clase bajo prueba es demasiado alta.

Debe tratar su prueba como un cliente de una pieza de código de la misma manera que otro código es un cliente de la misma. La prueba debe tener ciertas expectativas de cómo funciona el código, pero no debería tener que conocer los detalles. Si necesita saber demasiado sobre cómo funciona una clase para probarlo, probablemente deba haber otra capa de abstracción entre usted y el código que está probando.

Siéntase libre de crear capas abstractas solo para probar. El código de prueba es tan importante como el código de producción y debe escribirse y diseñarse como cualquier otra cosa. A veces, una capa de indirección puede hacer que sus pruebas sean menos frágiles y significa que cuando algo se rompe, el cambio solo se produce en un lugar.

0

Aquí hay un experimento mental. Parece una diatriba

Por el contrario, intente no realizar las pruebas de su unidad.

Luego, dígale a un ingeniero de una disciplina diferente que ha dejado que sus planes de prueba se queden en el camino. Que sus cambios ahora solo se prueban cuando todo se arregla.

(Por cierto este régimen de prueba tiene un nombre: "la integración big bang": cuando se intenta en Electrónica es literalmente una explosión que todo el equipo se incendia.)

Explicar la cantidad de trabajo que era mantener, y que no hacerlo ahorró tiempo.

Mira la expresión de sus caras. Para obtener el mejor efecto, elija a alguien que sea un PE con licencia (Ingeniero profesional) en su localidad.

Repita esto, pero sustituya a la persona de su auditor de ISO 9000, donde le mostrará el procedimiento de desarrollo revisado que no tiene pruebas hasta la integración.

Repita, nuevamente, sustituya a un asesor de CMMI. Este último será divertido. Los evaluadores de CMMI SCAMPI aman explicaciones como "fue demasiado esfuerzo"

Ahora, probablemente esté pensando que no trabaja en ningún lugar con ISO9000 o CMMI, y nunca trabaje con otros ingenieros de disipline.

En ese momento, el problema es que una tienda de software promedio probablemente no pruebe en absoluto.

Acepte el promedio y use las peores prácticas establecidas en la industria. Luego, la deslocalización a < inserte el país más barato que en el lugar donde vive > tampoco puede tener ningún impacto en la calidad (no hay un proceso peor). Entonces, realmente, su jefe debería trabajar fuera de la costa ahora y ahorrar dinero. Hay algo mal con este razonamiento en alguna parte.