Introducción: ¿Por qué el 100% de cobertura de código es una ilusión?
\n¿Alguna vez te has sentido orgulloso de un informe de PHPUnit que dice «Code Coverage: 98%»? Y luego lanzas una versión y en producción aparece un error crítico. ¿Te suena? El problema es que la cobertura clásica (line/statement coverage) solo mide qué líneas de código se ejecutaron. No verifica si tus tests realmente prueban la lógica.
\nImagina que escribes un test que verifica que una función devuelve true. Pero la función siempre devuelve true, incluso si la rompes. El test pasará, la cobertura será del 100%, pero no detectarás el error. Aquí es donde entra el mutation testing en PHP: una técnica que cambia la forma tradicional de pensar sobre las pruebas.
\nEn este artículo, veremos qué son las pruebas de mutación, cómo funcionan con código PHP real y cómo implementarlas en tu proyecto usando la librería Infection.
\n\n¿Qué es Mutation Testing? (Y por qué no es magia)
\nMutation testing (o pruebas de mutación) es un método para evaluar la calidad de los tests. Consiste en introducir pequeños cambios intencionales (mutaciones) en el código fuente. Si después del cambio el test falla, el mutante ha muerto y el test funciona. Si el test sigue pasando, el mutante ha sobrevivido, lo que significa que tu test no está verificando nada.
\nUna analogía simple: tú eres un guardia de seguridad y tus tests son las cámaras. El mutation testing introduce «intrusos» (mutantes) en el edificio. Si la cámara (el test) detecta al intruso, funciona. Si el intruso pasea tranquilamente, la cámara es inútil.
\nEn PHP, la herramienta principal para esto es Infection, una librería que ejecuta PHPUnit en cada mutante y analiza los resultados.
\n\n¿Cómo se ve en la práctica?
\nSupongamos que tienes una clase simple de calculadora:
\n<?php\nclass Calculator\n{\n public function add(int $a, int $b): int\n {\n return $a + $b;\n }\n}\nY su test correspondiente:
\n<?php\nuse PHPUnit\\Framework\\TestCase;\n\nclass CalculatorTest extends TestCase\n{\n public function testAdd()\n {\n $calc = new Calculator();\n $result = $calc->add(2, 3);\n $this->assertEquals(5, $result);\n }\n}\nLa herramienta Infection creará un mutante, reemplazando + por -:
return $a - $b;\nLuego ejecutará el test. Si el test falla, el mutante ha muerto. Si el test pasa (y pasará, porque solo verificas 2+3, no 2-3), el mutante ha sobrevivido. Esto es una señal: tu test no es lo suficientemente bueno.
\n\nInstalación de Infection y primer uso
\nPara empezar, instala Infection a través de Composer:
\ncomposer require --dev infection/infection\nLuego, crea un archivo de configuración infection.json (o ejecuta vendor/bin/infection para una configuración interactiva).
Ejemplo de configuración mínima:
\n{\n "source": {\n "directories": [\n "src"\n ]\n },\n "phpUnit": {\n "configDir": "."\n },\n "mutators": {\n "@default": true\n }\n}\nEjecuta las pruebas de mutación:
\nvendor/bin/infection --min-msi=100\nDonde --min-msi=100 indica que queremos que el 100% de los mutantes mueran (un objetivo ideal, pero raramente alcanzable). Infection generará un informe en formato HTML (carpeta infection.html), donde los mutantes supervivientes se marcarán en rojo.
Tipos de mutaciones en PHP (con ejemplos)
\nInfection admite decenas de mutadores. Estos son los más comunes con los que te encontrarás:
\n\n1. Operadores matemáticos
\nReemplazo de + por -, * por /, % por *, etc.
// Código original\nreturn $price * $quantity;\n\n// Mutante\nreturn $price / $quantity;\n
Blogs
Book Recommendations
Leer también
Primer programa en Python: ¿qué tan rápido puedes crearlo?
Cómo conectar PostgreSQL con Python: Guía práctica
Despliegue de Kotlin en Kubernetes: guía básica para principiantes
Optimización del rendimiento de aplicaciones Kotlin: para principiantes
De la idea al millón: cómo JavaScript cambia las reglas del juego en las startups