Pruebas de mutación con el ejemplo: Evolucionando a partir de la frágil DDT

| |

COMPARTE EL ARTÍCULO!!!

El desarrollo basado en pruebas no es suficiente para entregar un código lean que funcione exactamente de acuerdo a las expectativas. Las pruebas de mutación son un poderoso paso adelante. Esto es lo que parece.

binary_code_computer_screen.png

El tercer artículo de esta serie demostró cómo usar las pruebas de fallas y las pruebas unitarias para desarrollar un código mejor.

Aunque parecía que el viaje había terminado con un ejemplo exitoso de la aplicación Internet de las Cosas (IO) para controlar una puerta de gato, los programadores experimentados saben que las soluciones necesitan una mutación .

¿Qué son las pruebas de mutación?

La prueba de mutación es el proceso de iterar a través de cada línea de código implementado, mutar esa línea, luego ejecutar pruebas unitarias y verificar si la mutación rompió las expectativas. Si no lo ha hecho, ha creado un mutante sobreviviente.

Más recursos de DevOps

  • ¿Qué es DevOps?
  • La guía de contratación definitiva de DevOps
  • Guía de herramientas de monitorización de DevOps
  • Introducción a DevSecOps
  • Términos de DevOps: 10 conceptos esenciales
  • Últimos artículos de DevOps

Los mutantes supervivientes son siempre un problema alarmante que apunta a áreas potencialmente peligrosas en una base de código. En cuanto atrapen a un mutante superviviente, deben matarlo. Y la única manera de matar a un mutante superviviente es crear descripciones adicionales: nuevas pruebas unitarias que describan sus expectativas con respecto a la salida de su función o módulo.Al final, usted ofrece una solución lean, media, que es hermética y garantiza que no hay errores o defectos molestos en su base de código.

Si dejas que los mutantes sobrevivientes se muevan y proliferen, vivan mucho tiempo y prosperen, entonces estás creando la tan temida deuda técnica. Por otro lado, si alguna prueba unitaria se queja de que la línea de código mutada temporalmente produce una salida diferente de la salida esperada, el mutante ha muerto.

Instalación de Stryker

La forma más rápida de probar las pruebas de mutación es aprovechar un marco de trabajo dedicado. Este ejemplo utiliza Stryker.

Para instalar Stryker, vaya a la línea de comandos y ejecute:

$ dotnet tool install-g dotnet-stryker > Herramienta de instalación de dotnets

Para ejecutar Stryker, navegue hasta la carpeta unittest y escriba:

$ dotnet-stryker 

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>i

Aquí está el informe de Stryker sobre la calidad de nuestra solución:

> Progreso de las pruebas | 14/14 | 100% | ~0m 00s |
Muerto: 13
Sobrevivido : 1
Timeout : 0

> Todos los mutantes han sido probados, y su puntuación de mutación ha sido calculada
– app[13/14 (92,86%)]
[…]

El informe dice:

  • Stryker creó 14 mutantes
  • Stryker vio que 13 mutantes murieron en las pruebas unitarias
  • Stryker vio a un mutante sobrevivir al ataque de las pruebas unitarias
  • Stryker calculó que la base de código existente contiene 92,86% del código que cumple las expectativas
  • Stryker calculó que el 7,14% del código base contiene código que no cumple las expectativas

En general, Stryker afirma que la aplicación reunida en los tres primeros artículos de esta serie no logró producir una solución fiable.

Cómo matar a un mutante

Cuando los desarrolladores de software encuentran mutantes supervivientes, normalmente buscan el código implementado y buscan formas de modificarlo. Por ejemplo, en el caso de la aplicación de ejemplo para la automatización de puertas de gato, cambie la línea:

string trapDoorStatus =»Undetermined»;

a:

string trapDoorStatus ="";

y ejecutar a Stryker de nuevo. Un mutante ha sobrevivido:

Todos los mutantes han sido probados, y su puntuación de mutación ha sido calculada
– app[13/14 (92,86%)]
[…]
Mutación de cuerdas en la línea 4: «Stryker estaba aquí!»»
» […]

Esta vez, puedes ver que Stryker mutó la línea:

string trapDoorStatus ="";

en:

string trapDoorStatus =""Stryker estaba aquí!";

Este es un gran ejemplo de cómo funciona Stryker: muta cada línea de nuestro código, de una manera inteligente, para ver si hay más casos de prueba en los que tengamos que pensar. Nos obliga a considerar nuestras expectativas con mayor profundidad.

Derrotado por Stryker, puede intentar mejorar el código implementado añadiéndole más lógica:

Control de cadenas públicas (cadena dayOrNight){
) string trapDoorStatus =»Indeterminado»;
if(dayOrNight ==»Nighttime»){
trapDoorStatus =»Trampilla para gatos deshabilitada»;
elseif(dayOrNight ==»Daylight»){
trapDoorStatus =»Cat trap door enabled»;
}otra{
trapDoorStatus =»Indeterminado»;
}
> Trampa de retornoEstado de la puerta;
}>

Pero después de ejecutar Stryker de nuevo, verá que este intento creó un nuevo mutante:

– app[13/15 (86,67%)]
[…]
Mutación de cuerdas en la línea 4: «Indeterminado»$0027$0027 ==> $0027$0027″»$0027
[…]
Mutación de cuerdas en la línea 10: «Indeterminado» ==>»Indeterminado»»»
[…]

strykerreport.png

No se puede salir de este aprieto modificando el código implementado. Resulta que la única manera de matar a los mutantes supervivientes es describir expectativas adicionales . ¿Y cómo describe usted las expectativas? Escribiendo pruebas unitarias.

Prueba de éxito de la unidad

Es hora de añadir una nueva prueba unitaria. Dado que el mutante superviviente se encuentra en la línea 4, se da cuenta de que no ha especificado expectativas para la salida con el valor «Indeterminado».

Añadamos una nueva prueba unitaria:

[Hecho]
publicvoid GivenIncorrectTimeOfDayReturnUndetermined(){
var esperado ="Indeterminado";
var actual = catTrapDoor.Control("Entrada incorrecta");
Afirmar igual (esperado, real);
}

>

¡El arreglo funcionó! Ahora todos los mutantes son asesinados:

Todos los mutantes han sido probados, y su puntuación de mutación ha sido calculada
– app[14/14 (100%)]
[Muerto][…]

Finalmente tiene una solución completa, incluyendo una descripción de lo que se espera como salida si el sistema recibe valores de entrada incorrectos.

Pruebas de mutación al rescate

Suponga que decide sobredimensionar una solución y añade este método a la FakeCatTrapDoor :

privatestring getTrapDoorStatus(string dayOrNight){
estado de la cadena ="Todo bien";
if(dayOrNight !="Nighttime"||| dayOrNight !="Daylight"){
estado ="Indeterminado";
}
> estado de la devolución;
}

>

Luego reemplace el enunciado de la línea 4:

string trapDoorStatus =»Undetermined»;

con:

string trapDoorStatus = getTrapDoorStatus(dayOrNight);

Cuando haces pruebas unitarias, todo pasa:

Inicio de la ejecución de la prueba, por favor espere…

> Pruebas totales: 5. Aprobado: 5. Fallido: 0. Saltado: 0.
Prueba de funcionamiento exitosa.
Tiempo de ejecución de la prueba: 2.7191 segundos >

La prueba ha pasado sin problemas. TDD ha funcionado. Pero si traemos a Stryker a la escena, de repente la imagen se ve un poco sombría:

Todos los mutantes han sido probados, y su puntuación de mutación ha sido calculada
– app[14/20 (70%)]
[…]

Stryker creó 20 mutantes; 14 mutantes fueron asesinados, mientras que seis mutantes sobrevivieron. Esto reduce la puntuación de éxito al 70%. Esto significa que sólo el 70% de nuestro código está ahí para cumplir con las expectativas descritas. El otro 30% del código está ahí sin ninguna razón clara, lo que nos expone al riesgo de que se haga un uso indebido de ese código.

En este caso, Stryker ayuda a combatir el hinchazón. Desalienta el uso de lógica innecesaria y enrevesada porque está dentro de las grietas de esa lógica compleja innecesaria donde se reproducen los insectos y los defectos.

Conclusión

Como ha visto, las pruebas de mutación aseguran que ningún hecho incierto pase desapercibido.

Usted podría comparar a Stryker con un maestro de ajedrez que está pensando en todas las jugadas posibles para ganar una partida. Cuando Stryker no está seguro, le está diciendo que ganar no es todavía una garantía. Cuantas más pruebas unitarias registremos como hechos, más lejos estaremos en nuestro partido, y más probable será que Stryker pueda predecir una victoria. En cualquier caso, Stryker ayuda a detectar escenarios de pérdida incluso cuando todo se ve bien en la superficie.

Siempre es una buena idea diseñar el código correctamente. Usted ha visto cómo la TDD ayuda en ese sentido. TDD es especialmente útil cuando se trata de mantener su código extremadamente modular.Sin embargo, la TDD por sí sola no es suficiente para entregar código lean que funcione exactamente de acuerdo a las expectativas. Los desarrolladores pueden añadir código a una base de código ya implementada sin describir primero las expectativas. Eso pone en riesgo todo el código base. Las pruebas de mutación son especialmente útiles para detectar infracciones en la cadencia de desarrollo impulsado por pruebas (TDD) regulares. Necesita mutar cada línea de código implementado para asegurarse de que no haya ninguna línea de código sin una razón específica.

Ahora que entiendes cómo funciona la prueba de mutación, deberías estudiar cómo aprovecharla.La próxima vez, te mostraré cómo hacer un buen uso de las pruebas de mutación al abordar escenarios más complejos. También presentaré conceptos más ágiles para ver cómo la cultura DevOps puede beneficiarse de la maduración de la tecnología.

COMPARTE EL ARTÍCULO!!!

Previous

6 proyectos de Arduino para jugar en el Arduino Day

Lea esto antes de comprar cualquier curso Udemy

Next

Deja un comentario

shares