PHPUnit Basico
PHPUnit es el framework de testing mas utilizado en PHP. Proporciona herramientas para escribir y ejecutar tests de forma estructurada y profesional.
Instalacion
PHPUnit se instala como dependencia de desarrollo con Composer:
# Instalar PHPUnit como dependencia de desarrollo
composer require --dev phpunit/phpunit
# Verificar instalacion
./vendor/bin/phpunit --version
Estructura del proyecto
Por convencion, los tests se colocan en una carpeta tests/
separada del codigo fuente:
mi-proyecto/
├── src/
│ └── Calculadora.php
├── tests/
│ └── CalculadoraTest.php
├── composer.json
└── phpunit.xml
Configuracion basica
Crea un archivo phpunit.xml en la raiz del proyecto:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
bootstrap="vendor/autoload.php">
<testsuites>
<testsuite name="Tests">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>
Tu primer test con PHPUnit
Primero, el codigo que vamos a testear:
<?php
// src/Calculadora.php
declare(strict_types=1);
namespace App;
class Calculadora
{
public function sumar(int $a, int $b): int
{
return $a + $b;
}
public function restar(int $a, int $b): int
{
return $a - $b;
}
public function dividir(float $a, float $b): float
{
if ($b === 0.0) {
throw new \InvalidArgumentException('No se puede dividir entre cero');
}
return $a / $b;
}
}
Ahora el test correspondiente:
<?php
// tests/CalculadoraTest.php
declare(strict_types=1);
namespace Tests;
use App\Calculadora;
use PHPUnit\Framework\TestCase;
class CalculadoraTest extends TestCase
{
public function testSumarDosNumeros(): void
{
// Arrange
$calc = new Calculadora();
// Act
$resultado = $calc->sumar(2, 3);
// Assert
$this->assertSame(5, $resultado);
}
public function testRestarDosNumeros(): void
{
$calc = new Calculadora();
$resultado = $calc->restar(10, 4);
$this->assertSame(6, $resultado);
}
}
Las clases de test terminan en Test y extienden TestCase.
Los metodos de test empiezan con test o usan el atributo #[Test].
Ejecutar tests
# Ejecutar todos los tests
./vendor/bin/phpunit
# Ejecutar un archivo especifico
./vendor/bin/phpunit tests/CalculadoraTest.php
# Ejecutar un test especifico
./vendor/bin/phpunit --filter testSumarDosNumeros
La salida muestra el resultado de cada test:
PHPUnit 11.0.0
.. 2 / 2 (100%)
Time: 00:00.005, Memory: 6.00 MB
OK (2 tests, 2 assertions)
Assertions comunes
PHPUnit ofrece muchos metodos de asercion para verificar resultados:
<?php
declare(strict_types=1);
// Igualdad estricta (tipo y valor)
$this->assertSame(5, $resultado); // Pasa si 5 === $resultado
$this->assertNotSame(5, $resultado); // Pasa si 5 !== $resultado
// Igualdad no estricta
$this->assertEquals(5, $resultado); // Pasa si 5 == $resultado
// Booleanos
$this->assertTrue($valor);
$this->assertFalse($valor);
// Null
$this->assertNull($valor);
$this->assertNotNull($valor);
// Arrays
$this->assertCount(3, $array); // Tiene 3 elementos
$this->assertContains('a', $array); // Contiene 'a'
$this->assertArrayHasKey('id', $array); // Tiene clave 'id'
$this->assertEmpty($array); // Array vacio
// Strings
$this->assertStringContainsString('hola', $texto);
$this->assertStringStartsWith('Hola', $texto);
$this->assertMatchesRegularExpression('/\d+/', $texto);
// Tipos
$this->assertInstanceOf(Usuario::class, $objeto);
Testear excepciones
Para verificar que el codigo lanza excepciones cuando debe:
<?php
declare(strict_types=1);
namespace Tests;
use App\Calculadora;
use PHPUnit\Framework\TestCase;
class CalculadoraTest extends TestCase
{
public function testDividirEntreCeroLanzaExcepcion(): void
{
$calc = new Calculadora();
// Declarar que esperamos una excepcion
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('No se puede dividir entre cero');
// Este codigo debe lanzar la excepcion
$calc->dividir(10, 0);
}
}
Data providers
Los data providers permiten ejecutar el mismo test con diferentes datos:
<?php
declare(strict_types=1);
namespace Tests;
use App\Calculadora;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\DataProvider;
class CalculadoraTest extends TestCase
{
public static function datosParaSuma(): array
{
return [
'positivos' => [2, 3, 5],
'negativos' => [-2, -3, -5],
'mixtos' => [-5, 10, 5],
'con cero' => [0, 5, 5],
];
}
#[DataProvider('datosParaSuma')]
public function testSumaConDiferentesDatos(int $a, int $b, int $esperado): void
{
$calc = new Calculadora();
$resultado = $calc->sumar($a, $b);
$this->assertSame($esperado, $resultado);
}
}
PHPUnit ejecuta el test una vez por cada conjunto de datos, mostrando cual fallo si alguno no pasa.
setUp y tearDown
Estos metodos se ejecutan antes y despues de cada test, utiles para preparar y limpiar el entorno:
<?php
declare(strict_types=1);
namespace Tests;
use App\Calculadora;
use PHPUnit\Framework\TestCase;
class CalculadoraTest extends TestCase
{
private Calculadora $calculadora;
protected function setUp(): void
{
// Se ejecuta ANTES de cada test
$this->calculadora = new Calculadora();
}
protected function tearDown(): void
{
// Se ejecuta DESPUES de cada test
// Limpiar recursos, archivos temporales, etc.
}
public function testSumar(): void
{
// Ya tenemos $this->calculadora disponible
$this->assertSame(5, $this->calculadora->sumar(2, 3));
}
public function testRestar(): void
{
$this->assertSame(6, $this->calculadora->restar(10, 4));
}
}
Ejercicios
Ejercicio 1: Escribir un test basico
Escribe tests para esta clase:
<?php
declare(strict_types=1);
class StringHelper
{
public function invertir(string $texto): string
{
return strrev($texto);
}
public function contarPalabras(string $texto): int
{
return str_word_count($texto);
}
}
Ver solucion
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
class StringHelperTest extends TestCase
{
private StringHelper $helper;
protected function setUp(): void
{
$this->helper = new StringHelper();
}
public function testInvertirTexto(): void
{
$resultado = $this->helper->invertir('hola');
$this->assertSame('aloh', $resultado);
}
public function testInvertirTextoVacio(): void
{
$resultado = $this->helper->invertir('');
$this->assertSame('', $resultado);
}
public function testContarPalabras(): void
{
$resultado = $this->helper->contarPalabras('Hola mundo cruel');
$this->assertSame(3, $resultado);
}
public function testContarPalabrasTextoVacio(): void
{
$resultado = $this->helper->contarPalabras('');
$this->assertSame(0, $resultado);
}
}
Ejercicio 2: Test con excepcion
Escribe un test que verifique que esta funcion lanza una excepcion con edad negativa:
<?php
declare(strict_types=1);
class Persona
{
public function __construct(
public readonly string $nombre,
public readonly int $edad
) {
if ($edad < 0) {
throw new InvalidArgumentException('La edad no puede ser negativa');
}
}
}
Ver solucion
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
class PersonaTest extends TestCase
{
public function testCrearPersonaConDatosValidos(): void
{
$persona = new Persona('Ana', 25);
$this->assertSame('Ana', $persona->nombre);
$this->assertSame(25, $persona->edad);
}
public function testEdadNegativaLanzaExcepcion(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('La edad no puede ser negativa');
new Persona('Juan', -5);
}
}
Ejercicio 3: Data provider
Crea un data provider para testear esta funcion con multiples casos:
<?php
declare(strict_types=1);
function esMayorDeEdad(int $edad): bool
{
return $edad >= 18;
}
Ver solucion
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\DataProvider;
class EdadTest extends TestCase
{
public static function edadesProvider(): array
{
return [
'menor de edad (10)' => [10, false],
'justo menor (17)' => [17, false],
'justo mayor (18)' => [18, true],
'adulto (30)' => [30, true],
'anciano (80)' => [80, true],
];
}
#[DataProvider('edadesProvider')]
public function testEsMayorDeEdad(int $edad, bool $esperado): void
{
$resultado = esMayorDeEdad($edad);
$this->assertSame($esperado, $resultado);
}
}
Has encontrado un error o tienes una sugerencia para mejorar esta leccion?
EscribenosTe está gustando el curso?
Tenemos cursos premium con proyectos reales y soporte personalizado.
Descubrir cursos premium