Introducción: ¿por qué probar aplicaciones PHP?
Probar el código no es solo una tendencia moderna, sino una práctica fundamental del desarrollo profesional. En el mundo de PHP, donde una gran cantidad de proyectos trabajan con bases de datos, API externas y lógica de negocio compleja, la calidad del código afecta directamente la estabilidad y seguridad del producto. Sin pruebas, incluso un cambio pequeño puede romper una funcionalidad que ha funcionado durante años.
En este artículo, analizaremos tres niveles clave de pruebas: unit (pruebas unitarias), integration (pruebas de integración) y e2e (pruebas de extremo a extremo). Aprenderás en qué se diferencian, cuándo aplicar cada uno y verás ejemplos reales de código en PHP. Independientemente de si usas Laravel, Symfony o escribes en PHP puro, estos conocimientos te ayudarán a crear aplicaciones robustas.
Pruebas unitarias: verificación de componentes aislados
Las pruebas unitarias son el nivel más bajo y rápido de testing. Su objetivo es verificar el funcionamiento de un método o función individual en completo aislamiento de dependencias externas (base de datos, sistema de archivos, solicitudes HTTP).
Herramientas para pruebas unitarias en PHP
- PHPUnit — el estándar de facto. Potente, flexible, compatible con la mayoría de los frameworks.
- Pest — una alternativa moderna con una sintaxis más concisa. Ideal para principiantes y equipos que valoran la legibilidad.
Ejemplo con PHPUnit
Supongamos que tenemos una clase simple para calcular descuentos:
<?phpclass DiscountCalculator{ public function calculate(float $price, float $percent): float { if ($percent < 0 || $percent > 100) { throw new \\InvalidArgumentException('El porcentaje de descuento debe estar entre 0 y 100'); } return $price - ($price * $percent / 100); }}?>La prueba para esta clase se vería así:
<?phpuse PHPUnit\\Framework\\TestCase;
class DiscountCalculatorTest extends TestCase{ public function testCalculateWithValidDiscount(): void { $calculator = new DiscountCalculator(); $result = $calculator->calculate(1000, 20); $this->assertEquals(800.0, $result); }
public function testCalculateWithZeroPercent(): void { $calculator = new DiscountCalculator(); $result = $calculator->calculate(500, 0); $this->assertEquals(500.0, $result); }
public function testCalculateThrowsExceptionForInvalidPercent(): void { $this->expectException(\\InvalidArgumentException::class); $calculator = new DiscountCalculator(); $calculator->calculate(100, 150); }}?>Principios clave de las pruebas unitarias:
- Una prueba — una verificación (un assert).
- Las pruebas no deben depender unas de otras.
- Usa mocks para aislar servicios externos. Por ejemplo, con
createMock()en PHPUnit. - Cubre casos límite: null, cadenas vacías, valores negativos.
Pruebas de integración: verificación de la interacción entre componentes
Las pruebas de integración verifican cómo diferentes partes de la aplicación funcionan juntas: clases, bases de datos, servicios externos. A diferencia de las pruebas unitarias, aquí usamos dependencias reales (o casi reales).
¿Cuándo escribir pruebas de integración?
- Verificar la interacción con la base de datos (ORM, consultas).
- Trabajar con el sistema de archivos (carga/lectura de archivos).
- Interacción con API externas (mediante stubs de prueba).
- Verificar el correcto funcionamiento de repositorios y la capa de servicios.
Ejemplo en PHP usando PDO (sin framework)
<?phpuse PHPUnit\\Framework\\TestCase;
class User