En pocas palabras
Introduce errores deliberados para comprobar si las pruebas detectan cambios de comportamiento.
Qué problema resuelve
Cobertura alta con aserciones débiles o pruebas que siempre pasan.
Cuándo utilizarlo
Lógica crítica de negocio. Ejemplo: verificar que las pruebas detecten un límite de aprobación incorrecto.
De la idea a la práctica
Funcionamiento, ejemplos y decisiones para pasar al siguiente nivel.
En el Radar compartido: Trial (valoración de la edición aportada).
Cómo funciona
La herramienta cambia operadores, constantes o retornos y ejecuta pruebas. Un mutante eliminado provoca un fallo; uno superviviente puede revelar una validación ausente.
Ejemplo de uso
Cambiar una condición monto <= limite por monto < limite. Si ninguna prueba falla, añadir un caso exactamente en el límite y verificar tanto la decisión como sus efectos.
Puntuación de mutación
mutation score = mutantes eliminados / (mutantes totales − equivalentes)
A diferencia de la cobertura de líneas, que solo indica qué código se ejecutó, la puntuación de mutación indica qué cambios de comportamiento se detectaron. Una suite con 95 % de cobertura y aserciones débiles puede tener un 40 % de mutation score.
Operadores habituales
| Operador | Ejemplo |
|---|---|
| Límites condicionales | < → <= |
| Negación de condiciones | == → != |
| Matemáticos | + → -, * → / |
| Valores de retorno | return x → return 0 / null / true |
| Eliminación de llamadas | auditoria.registrar(e) → (nada) |
| Incrementos | i++ → i-- |
Herramientas por lenguaje
| Lenguaje | Herramienta | Ejecución |
|---|---|---|
| Java / Kotlin | PIT | mvn org.pitest:pitest-maven:mutationCoverage |
| JavaScript / TypeScript, C#, Scala | Stryker | npx stryker run |
| Python | mutmut, Cosmic Ray | mutmut run |
| Rust | cargo-mutants | cargo mutants |
Configuración de PIT con umbral
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<configuration>
<targetClasses><param>com.krediya.cartera.dominio.*</param></targetClasses>
<mutators><mutator>STRONGER</mutator></mutators>
<mutationThreshold>75</mutationThreshold>
<withHistory>true</withHistory> <!-- análisis incremental entre ejecuciones -->
<threads>4</threads>
</configuration>
<dependencies>
<dependency>
<groupId>org.pitest</groupId>
<artifactId>pitest-junit5-plugin</artifactId>
</dependency>
</dependencies>
</plugin>
Leer los supervivientes
| Superviviente | Probable causa | Acción |
|---|---|---|
< → <= en un límite |
Falta caso en el valor exacto | Prueba de frontera |
Eliminar llamada a notificar() |
No se verifica el efecto | Aserción sobre el mock o el evento |
return saldo → return 0 |
La prueba no comprueba el valor | Aserción sobre el resultado |
Cambio en un log.debug |
Código sin comportamiento observable | Excluir |
| Mutante equivalente (mismo comportamiento) | No hay prueba posible | Marcar y excluir |
Estrategia de adopción
Empieza por el dominio crítico (cálculo de intereses, reglas de aprobación), ejecuta en modo incremental sobre el código cambiado en cada PR y un análisis completo nocturno. Fija el umbral a partir de la línea base actual y súbelo gradualmente. Es también una excelente forma de evaluar pruebas escritas por agentes de IA: detecta pruebas que pasan sin comprobar nada.
Criterios de implementación
Empezar por módulos críticos con Stryker, PIT o cargo-mutants. Controlar duración, filtrar equivalentes justificados y priorizar mejoras de las aserciones sobre alcanzar una cifra arbitraria.
Continúa en las fuentes
Documentación oficial para verificar detalles y explorar más.