Pruebas de mutación con Infection
Mida la calidad real de sus pruebas
Pruebas de mutación con Infection es una lección gratuita de PHP Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de PHP Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de PHP Academy incluye 4 lecciones en total.
La cobertura miente
Una cobertura de líneas del 100 % resulta tranquilizadora, pero solo demuestra que sus pruebas ejecutaron el código, no que detectarían un error en él. Una prueba puede ejecutar una línea sin comprobar nada significativo. Las pruebas de mutación miden lo importante: ¿fallarían sus pruebas si el código estuviera sutilmente defectuoso? Infection es la herramienta estándar de PHP para esto.
composer require --dev infection/infectionLa idea central: los mutantes
Infection toma el código cubierto e introduce pequeños fallos: mutantes. Cambia > por >=, + por -, && por ||, elimina un return, etc. Después vuelve a ejecutar las pruebas contra cada mutante:
- Si una prueba falla → el mutante es eliminado (bien: sus pruebas detectaron el fallo).
- Si todas las pruebas pasan → el mutante sobrevive (mal: un error real en ese punto pasaría inadvertido).
Un superviviente en acción
Considere esta función y una prueba débil. Infection transformaría >= en >. Si ninguna prueba comprueba el límite exacto (cuando el importe es igual al umbral), ese mutante sobrevive, lo que revela un caso extremo no probado.
<?php
function qualifiesForFreeShipping(float $total): bool
{
return $total >= 50.0; // Infection mutates >= to >
}
// Weak test only checks 100 and 10 -> never tests exactly 50.0
var_dump(qualifiesForFreeShipping(100.0)); // true
var_dump(qualifiesForFreeShipping(10.0)); // false
var_dump(qualifiesForFreeShipping(50.0)); // true <-- the boundary the mutant exposes
Eliminar el mutante
Añada la aserción del límite y el mutante >= a > muere: con el código mutado, 50.0 > 50.0 es false, por lo que la prueba falla, exactamente lo que queremos. Las pruebas de mutación le indican literalmente qué aserciones faltan.
<?php
use PHPUnit\Framework\TestCase;
final class ShippingTest extends TestCase
{
public function test_threshold_is_inclusive(): void
{
// Kills the >= -> > mutant
self::assertTrue(qualifiesForFreeShipping(50.0));
}
}
Configuración: infection.json
Infection se controla mediante infection.json5. Declare qué directorios se deben mutar, dónde se almacenan los registros y los umbrales mínimos de puntuación para que CI se considere correcto. Dirija source.directories únicamente al código de producción, nunca a sus pruebas.
{
"source": {
"directories": ["src"]
},
"logs": {
"text": "build/infection.log",
"html": "build/infection.html"
},
"mutators": {
"@default": true
},
"minMsi": 80,
"minCoveredMsi": 90
}Las métricas MSI
Infection informa del indicador de puntuación de mutación:
- MSI = mutantes eliminados / mutantes totales. Se ve penalizado por el código no cubierto (esos mutantes no pueden eliminarse).
- MSI cubierto = mutantes eliminados / mutantes en líneas cubiertas. Mide la calidad de sus aserciones allí donde sí realiza pruebas.
- Cobertura de código de mutación = cuánto código pudo mutar Infection.
Una cobertura de líneas alta con un MSI cubierto bajo es la señal clásica de pruebas con pocas aserciones.
Ejecutar Infection de forma eficiente
Las pruebas de mutación son costosas: vuelven a ejecutar el conjunto de pruebas una vez por cada mutante. Dos grandes mejoras de velocidad son ejecutar las pruebas en paralelo con --threads y mutar únicamente el código modificado por la rama actual mediante el filtrado del diff de Git, algo ideal para CI en solicitudes de incorporación de cambios.
vendor/bin/infection --threads=max --git-diff-lines --git-diff-base=origin/mainLeer los supervivientes
El valor está en el diff que Infection imprime para cada mutante superviviente. Muestra la línea exacta y el cambio que sus pruebas no detectaron. Trate los supervivientes como una lista de tareas: añada la aserción que falta o reconozca que el mutante es inofensivo (un mutante equivalente).
- return $total >= 50.0;
+ return $total > 50.0;
# Mutant survived: no test asserts the inclusive boundary (total === 50.0)Mutantes equivalentes y exclusión
Algunos mutantes son equivalentes: cambian el código, pero no su comportamiento observable, por lo que ninguna prueba podría eliminarlos. No se pueden eliminar y reducen injustamente el MSI. Suprima los mutadores que se sabe que producen falsos positivos en código específico, en lugar de manipular las pruebas para perseguirlos.
{
"mutators": {
"@default": true,
"Plus": {
"ignore": ["App\\Math\\Statistics::variance"]
}
}
}Dónde compensa usar pruebas de mutación
Como son lentas, diríjalas bien:
- Aplíquelas a la lógica central del dominio: precios, permisos y cálculos, donde los errores silenciosos resultan costosos.
- Condicione las solicitudes de incorporación de cambios al MSI cubierto de las líneas modificadas, no al repositorio completo.
- No persiga el 100 % global; los beneficios decrecientes y los mutantes equivalentes hacen que no sea rentable.
- Utilícelas para encontrar aserciones débiles y después corregir las pruebas: la puntuación es un medio, no el objetivo.
Necesita datos de cobertura para ser rápido
Infection solo muta las líneas que sus pruebas cubren realmente, por lo que reutiliza la cobertura del ejecutor de pruebas. Con Xdebug esto es lento; pcov es considerablemente más rápido para la cobertura de líneas y es el controlador recomendado para las ejecuciones de mutación. Infection también puede generar la cobertura por sí mismo o consumir un informe de cobertura que ya haya producido en CI.
# Faster mutation runs: use pcov instead of Xdebug for coverage
php -d pcov.enabled=1 vendor/bin/infection --threads=max
# Or reuse coverage already generated by your PHPUnit step:
vendor/bin/infection --coverage=build/coverage --skip-initial-testsComprobación rápida
¿Qué le indica un mutante superviviente?
Resumen
Ha aprendido a medir la calidad de las pruebas, no solo la cantidad:
- Las pruebas de mutación inyectan pequeños fallos (mutantes); eliminado = detectado, superviviente = una carencia.
- La cobertura muestra la ejecución; el MSI cubierto muestra la solidez de las aserciones.
- Configure mediante
infection.json5con umbrales de MSI; ejecute con--threadsy filtrado por diff de Git para ganar velocidad. - Los supervivientes son una lista de tareas; tenga en cuenta los mutantes equivalentes e ignórelos deliberadamente.
- Dirija las pruebas a la lógica central y condicione las solicitudes de incorporación de cambios al MSI de las líneas modificadas, en lugar de perseguir un 100 % global.
Preguntas frecuentes
¿La lección «Pruebas de mutación con Infection» es gratis?
Sí — el texto completo de «Pruebas de mutación con Infection» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de PHP Academy, actualiza a CoddyKit PRO. El curso de PHP Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Pruebas de mutación con Infection»?
Mida la calidad real de sus pruebas Practicas PHP Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar PHP Academy?
No se requiere experiencia previa. PHP Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Pruebas de mutación con Infection»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de PHP Academy?
Sí. Cada lección de PHP Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- El flujo de trabajo del desarrollo guiado por pruebas
- Mocks y stubs con Mockery
- Pruebas de integración y funcionales
- Pruebas de mutación con Infection