Aprende Laravel: Testing con Pest

Los tests verifican que tu app hace lo que debe, hoy y después de cada cambio, y son lo que mantiene en pie todo lo que armaste en los posts anteriores. Laravel viene con soporte para Pest y PHPUnit de fábrica, con un phpunit.xml ya configurado. En esta serie usamos Pest por su sintaxis limpia.
Feature vs Unit: cuál escribir
Tu carpeta tests trae dos directorios:
tests/Unit: prueban una porción muy chica y aislada de tu código (normalmente un método). No arrancan la app, así que no acceden a la base de datos.tests/Feature: prueban una porción más grande, incluyendo una petición HTTP completa a un endpoint.
La regla oficial: la mayoría de tus tests deberían ser de Feature. Son los que más confianza dan de que el sistema funciona como conjunto.
Crear un test
Con Artisan. Por defecto se crea en tests/Feature:
php artisan make:test UserTestPara uno de Unit, agrega --unit:
php artisan make:test CalculadoraTest --unitUn test con Pest
La sintaxis de Pest es una función, sin clases ni boilerplate:
<?php
test('la suma funciona', function () {
expect(1 + 1)->toBe(2);
});También puedes escribirlo con it(), que se lee más natural:
it('devuelve verdadero', function () {
expect(true)->toBeTrue();
});Tests HTTP: probar una ruta de verdad
Un test de Feature puede hacer peticiones a tus rutas. Dentro del closure tienes helpers como $this->get() y aserciones expresivas:
it('muestra la home', function () {
$response = $this->get('/');
$response->assertOk(); // status 200
$response->assertSee('Bienvenido');
});Aserciones que vas a usar seguido: assertOk(), assertStatus(201), assertSee('texto'), assertRedirect('/login').
Tocar la base de datos: RefreshDatabase
Cuando un test crea o consulta datos, necesitas una base limpia en cada corrida. El trait RefreshDatabase se encarga: si el esquema está al día no vuelve a migrar, y corre cada test dentro de una transacción que se descarta al terminar. En Pest se activa al tope del archivo:
<?php
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()->use(RefreshDatabase::class);
it('crea un post', function () {
$this->post('/posts', [
'title' => 'Mi primer post',
'body' => 'Contenido de prueba',
]);
$this->assertDatabaseHas('posts', [
'title' => 'Mi primer post',
]);
});assertDatabaseHas() confirma que la fila quedó guardada. Laravel usa el driver array para sesión y caché durante los tests, así que nada de eso ensucia tu entorno real.
Correr los tests
Tres formas equivalentes:
php artisan test # reporte detallado, la más cómoda
./vendor/bin/pest # el runner de Pest directo
./vendor/bin/phpunit # el runner de PHPUnitEl comando php artisan test acepta opciones útiles como --filter (correr un test puntual), --parallel (en varios procesos, requiere el paquete brianium/paratest) o --coverage (cobertura, requiere Xdebug o PCOV).
El ciclo completo
Cuando pides código a un agente de IA en tu proyecto Laravel, los tests son el contrato. Un cambio "terminado" que no pasa php artisan test no está terminado. Escribe el test, míralo fallar, escribe el código, míralo pasar.
Siguiente paso
Ya sabes probar que tu app funciona. Ahora toca ordenar la interfaz en piezas reutilizables: sigue con Aprende Laravel: Componentes de Blade o vuelve al índice en Aprende Laravel desde cero.
Preguntas frecuentes
¿Pest o PHPUnit para Laravel?
Los dos vienen soportados de fábrica. Pest tiene una sintaxis más limpia (funciones test() / it() en vez de clases), y es la que usamos en esta serie. Por debajo, Pest corre sobre PHPUnit.
¿Cuál es la diferencia entre un test de Feature y uno de Unit?
Los de Unit prueban una pieza aislada (un método) sin arrancar la app ni la base de datos. Los de Feature prueban un flujo completo, incluida una petición HTTP. La mayoría de tus tests deberían ser de Feature.
¿Cómo pruebo que una ruta responde bien?
Con un test de Feature: $this->get('/ruta') y aserciones como assertOk() o assertSee('texto').
¿Para qué sirve RefreshDatabase?
Corre cada test dentro de una transacción de base de datos (y migra solo si el esquema no está al día), así los tests que crean o consultan datos parten siempre de un estado conocido. En Pest se activa con pest()->use(RefreshDatabase::class).
¿Cómo corro los tests?
Con php artisan test (reporte detallado), ./vendor/bin/pest o ./vendor/bin/phpunit. Puedes filtrar con --filter, paralelizar con --parallel o medir cobertura con --coverage.
Recursos adicionales
Fuentes
- Testing: Getting Started | Laravel 13.x (documentación oficial de Laravel)
- Database Testing | Laravel 13.x (documentación oficial de Laravel)
- HTTP Tests | Laravel 13.x (documentación oficial de Laravel)
- Writing Tests | Pest (documentación oficial de Pest)
- composer.json de Pest 4.x (repositorio oficial de Pest)
¿Tienes un proyecto en mente?
Trabajo con Laravel, WordPress, SEO técnico y servidores MCP. El primer paso es una llamada de descubrimiento, sin costo ni compromiso, donde me cuentas qué necesitas y te digo con honestidad si puedo ayudarte.