Pruebas de mutación en PHP: matando tests para que funcionen

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Tus pruebas son una ilusión de seguridad?



Imagina: tienes un 95% de cobertura de código, todas las pruebas en verde, el CI/CD pasa. Estás seguro de que tu código PHP está protegido contra regresiones. ¿Pero es realmente así?



Yo mismo viví en esta ilusión durante mucho tiempo, hasta que me encontré con una situación: la prueba pasaba, aunque accidentalmente cambié && por || en una condición crítica. La prueba simplemente no verificaba esa rama. La cobertura era del 100%, pero la lógica no.



Conoce: pruebas de mutación (mutation testing) — una metodología que "mata" sin piedad tus pruebas para descubrir qué tan confiables son realmente. En este artículo, analizaremos cómo aplicarla en PHP usando la poderosa herramienta Infection, y por qué esto cambia las reglas del juego.



¿Qué son las pruebas de mutación y para qué sirven?



Las pruebas de mutación son un enfoque en el que se introducen pequeños cambios intencionales (mutaciones) en tu código fuente. Por ejemplo, el operador + se cambia por -, true por false, o se elimina una línea completa. Después de cada mutación, se ejecutan tus pruebas.



Si la prueba falla — la mutación está "muerta", lo que significa que la prueba realmente verifica esa parte del código. Si la prueba pasa — la mutación "sobrevive". Esto es una señal de alerta: o la prueba no verifica esa condición, o está mal escrita.



A diferencia de la métrica de "cobertura de código" (code coverage), que solo muestra qué líneas se ejecutaron, las pruebas de mutación verifican la calidad de las comprobaciones. Un alto porcentaje de cobertura no es una garantía, mientras que el puntaje de mutación (Mutation Score Indicator, MSI) es un indicador real de confiabilidad.



¿Por qué es importante para un desarrollador PHP?

  • Detección de pruebas "muertas" — aquellas que siempre están en verde pero no verifican nada.
  • Identificación de vacíos en la lógica — por ejemplo, condiciones límite omitidas.
  • Mayor confianza al refactorizar — sabes exactamente qué pruebas protegen el código.
  • Ahorro de tiempo — en lugar de auditar pruebas manualmente, obtienes un informe automático.


Herramientas para pruebas de mutación en PHP



El líder en el ámbito PHP es Infection (anteriormente conocido como Humbug). Se integra fácilmente con PHPUnit y Pest, admite múltiples mutaciones y proporciona informes claros.



Otras opciones: Humbug (el predecesor, pero menos activo) y Mutagen (experimental). Nos centraremos en Infection, que es el estándar moderno.



Práctica: configurando Infection en un proyecto



Instalemos Infection y ejecutémoslo en un ejemplo real. Supongamos que tenemos una clase simple para calcular un descuento:



<?php// src/DiscountCalculator.phpclass DiscountCalculator{    public function calculate(float $price, bool $isPremium): float    {        if ($isPremium) {            return $price * 0.9; // descuento del 10%        }

return $price; }}


Y su prueba:



<?php// tests/DiscountCalculatorTest.phpuse PHPUnit\\Framework\\TestCase;

class DiscountCalculatorTest extends TestCase{ public function testPremiumDiscount(): void { $calculator = new DiscountCalculator(); $result = $calculator->calculate(100.0, true); $this->assertEquals(90.0, $result); }

public function testRegularPrice(): void { $calculator = new DiscountCalculator(); $result = $calculator->calculate(100.0, false); $this->assertEquals(100.0, $result); }}


Cobertura: 100%. Pero verifiquemos con mutaciones.



Instalación y ejecución de Infection



composer require --dev infection/infection./vendor/bin/infection


Después de

Blogs

Book Recommendations