it-swarm-es.com

¿Es la cobertura de prueba una medida adecuada de la calidad del código?

Si tengo un código que tiene una cobertura de prueba del 80% (todas las pruebas pasan), ¿es justo decir que es de mayor calidad que el código sin cobertura de prueba?

¿O es justo decir que es más fácil de mantener?

21
David_001

En un sentido estricto, no es justo hacer ninguna afirmación hasta que se establezca la calidad del conjunto de pruebas. Pasar el 100% de las pruebas no tiene sentido si la mayoría de las pruebas son triviales o repetitivas entre sí.

La pregunta es: En la historia del proyecto, ¿alguna de esas pruebas descubrió errores? El objetivo de una prueba es encontrar errores. Y si no lo hicieron, fallaron como pruebas. En lugar de mejorar la calidad del código, es posible que solo le brinden una falsa sensación de seguridad.

Para mejorar sus diseños de prueba, puede utilizar (1) técnicas de caja blanca, (2) técnicas de caja negra y (3) pruebas de mutación.

(1) Aquí hay algunas buenas técnicas de caja blanca para aplicar a sus diseños de prueba. Una prueba de caja blanca se construye teniendo en cuenta un código fuente específico. Un aspecto importante de las pruebas de caja blanca es la cobertura del código:

  • ¿Se llama a todas las funciones? [Cobertura funcional]
  • ¿Se ejecuta cada declaración? [Cobertura del estado de cuenta: tanto la cobertura funcional como la cobertura del estado de cuenta son muy básicas, pero mejor que nada]
  • Para cada decisión (como if o while), ¿tiene una prueba que la obligue a ser verdadera y otra que la obligue a ser falsa? [Cobertura de decisiones]
  • Para cada condición que es una conjunción (usa &&) o disyunción (usa ||), ¿cada subexpresión tiene una prueba donde es verdadero/falso? [Cobertura de condición]
  • Cobertura de bucle: ¿Tiene una prueba que fuerza 0 iteraciones, 1 iteración, 2 iteraciones?
  • ¿Se cubre cada break de un bucle?

(2) Las técnicas de caja negra se utilizan cuando los requisitos están disponibles, pero el código en sí no lo está. Estos pueden conducir a pruebas de alta calidad:

  • ¿Sus pruebas de caja negra cubren múltiples objetivos de prueba? Querrá que sus pruebas sean "gordas": no solo prueban la característica X, sino que también prueban Y y Z. La interacción de diferentes características es una excelente manera de encontrar errores.
  • El único caso en el que no desea pruebas "gordas" es cuando está probando una condición de error. Por ejemplo, prueba de entrada de usuario no válida. Si trató de lograr varios objetivos de prueba de entrada no válidos (por ejemplo, un código postal no válido y una dirección postal no válida) es probable que un caso enmascare el otro.
  • Considere los tipos de entrada y forme una "clase de equivalencia" para los tipos de entradas. Por ejemplo, si su código prueba para ver si un triángulo es equilátero, la prueba que usa un triángulo con lados (1, 1, 1) probablemente encontrará los mismos tipos de errores que los datos de prueba (2, 2, 2) y (3, 3, 3) encontrará. Es mejor dedicar su tiempo a pensar en otras clases de aportes. Por ejemplo, si su programa maneja impuestos, querrá una prueba para cada tramo impositivo. [Esto se llama partición de equivalencia].
  • Los casos especiales a menudo se asocian con defectos. Los datos de la prueba también deben tener valores de límite, como los que se encuentran en, por encima o por debajo de los límites de una tarea de equivalencia. Por ejemplo, al probar un algoritmo de clasificación, querrá probar con una matriz vacía, una matriz de un solo elemento, una matriz con dos elementos y luego una matriz muy grande. Debe considerar los casos de límites no solo para la entrada, sino también para la salida. [Esto es análisis de valor límite de llamada.]
  • Otra técnica es "Adivinar errores". ¿Tiene la sensación de que si prueba alguna combinación especial puede hacer que su programa se rompa? ¡Entonces pruébalo! Recuerde: Su objetivo es encontrar errores, no confirmar que el programa es válido. Algunas personas tienen la habilidad de adivinar errores.

(3) Finalmente, suponga que ya tiene muchas pruebas de Nice para la cobertura de caja blanca y técnicas de caja negra aplicadas. ¿Qué más puedes hacer? Es hora de Probar sus pruebas. Una técnica que puede utilizar es la prueba de mutaciones.

En la prueba de mutación, realiza una modificación (una copia de) su programa, con la esperanza de crear un error. Una mutación puede ser:

Cambiar una referencia de una variable a otra variable; Inserte la función abs (); Cambiar menor que a mayor que; Eliminar una declaración; Reemplazar una variable con una constante; Eliminar un método primordial; Eliminar una referencia a un súper método; Cambiar el orden de los argumentos

Cree varias docenas de mutantes, en varios lugares de su programa [el programa aún deberá compilarse para poder probarlo]. Si sus pruebas no encuentran estos errores, ahora necesita escribir una prueba que pueda encontrar el error en la versión mutada de su programa. Una vez que una prueba encuentra el error, has matado al mutante y puedes probar con otro.


Addendum: Olvidé mencionar este efecto: Los errores tienden a agruparse. Lo que eso significa es que cuantos más errores encuentre en un módulo, mayor será la probabilidad de que encuentre más errores. Entonces, si tiene una prueba que falla (es decir, la prueba es exitosa, ya que el objetivo es encontrar errores), no solo debe corregir el error, sino que también debe escribir más pruebas para el módulo, utilizando el técnicas anteriores.

Mientras encuentre errores a un ritmo constante, los esfuerzos de prueba deben continuar. Solo cuando haya una disminución en la tasa de nuevos errores encontrados, debe tener la confianza de que ha realizado buenos esfuerzos de prueba para esa fase de desarrollo.

25
Macneil

El código sin absolutamente ninguna prueba puede ser de alta calidad, legible, hermoso y eficiente (o basura total), así que no, no es justo decir que el código con una cobertura de prueba del 80% es de mayor calidad que el código sin cobertura de prueba.

Podría ser justo decir que el código cubierto al 80% con bueno pruebas es probablemente de calidad aceptable, y probablemente relativamente mantenible. Pero realmente garantiza poco.

7
Joonas Pulakka

Según una definición, es más fácil de mantener, ya que es más probable que las pruebas detecten cualquier cambio importante.

Sin embargo, el hecho de que el código pase las pruebas unitarias no significa que sea intrínsecamente de mayor calidad. Es posible que el código aún tenga un formato incorrecto con comentarios irrelevantes y estructuras de datos inapropiadas, pero aún puede pasar las pruebas.

Sé qué código prefiero mantener y ampliar.

7
ChrisF

Yo lo llamaría más refactorable. La refactorización se vuelve extremadamente fácil si el código se cubre con muchas pruebas.

Sería justo llamarlo más fácil de mantener.

3
Josip Medved

Estoy de acuerdo con la parte mantenible. Michael Feathers publicó recientemente un video de una excelente charla llamada " La profunda sinergia entre la capacidad de prueba y el buen diseño " en la que analiza este tema. En la charla, dice que la relación es unidireccional, es decir, el código que está bien diseñado es comprobable, pero el código comprobable no está necesariamente bien diseñado.

Vale la pena señalar que la transmisión de video no es excelente en el video, por lo que podría valer la pena descargarlo si desea verlo en su totalidad.

2
Paddyslacker