Saltar al contenido
SDETRole
SDETRole

Glosario · Fundamentos de testing

Pruebas de mutación

En inglés: Mutation testing

También llamado: prueba de mutación, análisis de mutación, mutation score, puntuación de mutación

Definición

Técnica que introduce pequeños errores deliberados (mutantes) en el código y vuelve a ejecutar los tests para medir si la suite realmente detecta fallos.

Las pruebas de mutación (mutation testing) ponen a prueba tus tests. Una herramienta crea muchas copias del código, cada una con un pequeño cambio, como >= convertido en >, + en -, o el cuerpo de un método sustituido por return null. Cada copia modificada es un mutante. La suite de tests se ejecuta contra cada mutante. Si al menos un test falla, el mutante queda eliminado (killed). Si todos los tests siguen pasando, el mutante sobrevive, lo que significa que los tests no detectarían ese bug.

Puntuación de mutación (mutation score) = mutantes eliminados / total de mutantes (excluidos los mutantes equivalentes).

Ejemplo

boolean isAdult(int age) {
    return age >= 18;
}

Tests: isAdult(30) es verdadero, isAdult(10) es falso. La cobertura de líneas y de ramas es del 100 %.

La herramienta crea un mutante con age > 18. Ambos tests siguen pasando, así que el mutante sobrevive. Eso revela que falta una prueba de valor límite: nadie comprobó isAdult(18). Al añadirla, el mutante queda eliminado. La cobertura no podía decirte esto; las pruebas de mutación sí.

Herramientas

  • Java: PIT (pitest), con plugins para Maven y Gradle y soporte para JUnit 5.
  • JavaScript/TypeScript: StrykerJS, que también tiene versiones para .NET y Scala.
  • Python: mutmut y Cosmic Ray.

Límites prácticos

  • Coste. Cada mutante supone una ejecución de tests. Las herramientas lo reducen ejecutando solo los tests que cubren la línea mutada y trabajando de forma incremental sobre el código modificado, pero sigue siendo mucho más lento que una ejecución normal. La mayoría de los equipos lo ejecuta cada noche o sobre los archivos cambiados en un pull request, no en cada commit para todo el código.
  • Mutantes equivalentes. Algunos cambios no alteran el comportamiento en absoluto; por ejemplo, convertir i < n en i != n en un bucle donde i siempre avanza de uno en uno desde un valor menor que n. Ningún test puede eliminarlos, así que hay que revisarlos y excluirlos a mano.
  • Rinde mejor a nivel unitario. Las pruebas de mutación están pensadas para tests unitarios rápidos y deterministas. Ejecutarlas contra tests de UI lentos rara vez es práctico.

Usa los mutantes supervivientes como lista de tareas de aserciones que faltan, sobre todo en la lógica de negocio, en lugar de perseguir una puntuación perfecta.

Escribe para buscar en todo SDETRole.

Búsqueda de texto completo con Pagefind · se ejecuta en tu navegador Abrir la página de búsqueda →