Aprende Laravel: Testing con Pest

Llegaste al último fundamento, y es el que hace que todo lo anterior aguante en el tiempo: los tests verifican que tu app hace lo que debe, hoy y después de cada cambio. 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
Aquí está el valor real de los tests de Feature. 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 migra una base de datos fresca por test. En Pest se activa al tope del archivo:
<?php
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(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 directoEl comando php artisan test acepta opciones útiles como --filter (correr un test puntual), --parallel (en varios procesos) o --coverage (cobertura, requiere Xdebug o PCOV).
El ciclo completo
Este es el cierre de la serie: 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
Completaste los fundamentos de Laravel. El salto natural ahora es sumarle IA a tu flujo: mira IA para desarrolladores Laravel 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?
Migra una base de datos limpia en cada test, así los tests que crean o consultan datos parten siempre de un estado conocido. En Pest se activa con uses(RefreshDatabase::class).
¿Cómo corro los tests?
Con php artisan test (reporte detallado) o ./vendor/bin/pest. Puedes filtrar con --filter, paralelizar con --parallel o medir cobertura con --coverage.