> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Empieza a testear Laravel con Pest PHP

> Presentamos Pest PHP, predeterminado desde Laravel 11, desde el punto de vista de un ingeniero senior. Explicamos las diferencias con PHPUnit, el coste de migración y el uso de los tests `arch()`, pensando en su adopción en proyectos reales.

## ¿Por qué Pest pasó a ser el valor por defecto en Laravel?

Desde Laravel 11, al crear un proyecto con `laravel new`, **Pest** se selecciona como framework de testing por defecto. PHPUnit se ha usado durante años como herramienta de testing estándar de PHP, pero Pest se apoya en PHPUnit y ofrece una notación de tests más concisa y legible.

<Info>
  Como Pest se ejecuta sobre PHPUnit, los tests PHPUnit existentes pueden ejecutarse tal cual. La migración se puede hacer de forma progresiva.
</Info>

Detrás de la decisión oficial de adoptar Pest está el objetivo de reducir la fricción a la hora de escribir tests. Al eliminar los pasos ceremoniosos de definir una clase, escribir métodos, etc., y ofrecer una notación que permite concentrarse en "lo que quieres testear", el hábito de escribir tests se adquiere de forma natural.

***

## Diferencias principales con PHPUnit

### Notación de los tests

La diferencia más evidente es la forma de escribir los tests.

<Tabs>
  <Tab title="Pest">
    ```php theme={null}
    test('el usuario puede iniciar sesión', function () {
        $user = User::factory()->create();

        $response = $this->post('/login', [
            'email' => $user->email,
            'password' => 'password',
        ]);

        $response->assertRedirect('/dashboard');
    });
    ```
  </Tab>

  <Tab title="PHPUnit">
    ```php theme={null}
    class AuthTest extends TestCase
    {
        public function test_user_can_login(): void
        {
            $user = User::factory()->create();

            $response = $this->post('/login', [
                'email' => $user->email,
                'password' => 'password',
            ]);

            $response->assertRedirect('/dashboard');
        }
    }
    ```
  </Tab>
</Tabs>

La función `test()` de Pest recibe un closure. Al no necesitar definir clase ni método, la intención del test queda clara desde la primera línea. `it()` se puede usar de la misma manera. Cuando se escribe en inglés, se lee como una frase natural: `it('can login', ...)`.

### API `expect()`

La mayor característica de Pest es la aserción en formato encadenado con `expect()`.

```php theme={null}
test('la API de listado de posts devuelve JSON', function () {
    $posts = Post::factory(3)->create();

    $response = $this->getJson('/api/posts');

    expect($response->status())->toBe(200);
    expect($response->json('data'))->toHaveCount(3);
    expect($response->json('data.0.title'))->not->toBeEmpty();
});
```

Puedes escribir aserciones en un formato que se lee de forma natural, con `expect($value)->toBe()`, `->toBeNull()`, `->toContain()`, `->toHaveCount()`, etc. También puedes agrupar varias aserciones con encadenamiento de métodos.

```php theme={null}
expect($user)
    ->name->toBe('Juan Pérez')
    ->email->toBe('jperez@example.com')
    ->is_admin->toBeFalse();
```

### Setup y teardown

El equivalente a `setUp()` de PHPUnit es `beforeEach()`, y el de `tearDown()` es `afterEach()`.

```php theme={null}
beforeEach(function () {
    $this->user = User::factory()->create();
    $this->actingAs($this->user);
});

test('los usuarios autenticados pueden acceder al perfil', function () {
    $response = $this->get('/profile');
    $response->assertOk();
});

test('los usuarios autenticados pueden actualizar el perfil', function () {
    $response = $this->patch('/profile', ['name' => 'Nombre nuevo']);
    $response->assertRedirect('/profile');
});
```

### Datasets — tests table-driven

Para ejecutar la misma lógica de test con varios datos, se usa `dataset`.

```php theme={null}
test('las direcciones de correo inválidas dan error de validación', function (string $email) {
    $response = $this->postJson('/api/users', [
        'name' => 'Juan Pérez',
        'email' => $email,
    ]);

    $response->assertUnprocessable();
})->with([
    'sin email' => [''],
    'formato incorrecto' => ['notanemail'],
    'doble @' => ['a@@example.com'],
]);
```

Como la etiqueta de cada dataset (`'sin email'`, etc.) se añade al nombre del test, sabes de un vistazo con qué patrón ha fallado.

***

## Tests `arch()` — Comprobación automática de la arquitectura

`arch()` de Pest son tests que verifican la estructura del código base. Puedes verificar automáticamente reglas de arquitectura como "los controladores no dependen directamente de los modelos" o "los modelos heredan de Eloquent".

```php theme={null}
test('los modelos heredan de Eloquent', function () {
    arch()->expect('App\Models')
        ->toExtend(Illuminate\Database\Eloquent\Model::class);
});

test('los controladores están definidos como final', function () {
    arch()->expect('App\Http\Controllers')
        ->toBeFinal();
});

test('las clases de servicio no dependen de los controladores', function () {
    arch()->expect('App\Services')
        ->not->toUse('App\Http\Controllers');
});
```

<Tip>
  Los tests `arch()` se ejecutan mediante análisis estático del código fuente. Al no enviar peticiones HTTP reales ni acceder a la base de datos, son muy rápidos.
</Tip>

Pest también incluye presets con reglas de arquitectura de uso frecuente.

```php theme={null}
test('cumple con las reglas de arquitectura de Laravel', function () {
    arch()->preset()->laravel();
});
```

El preset `laravel()` verifica en bloque reglas alineadas con las convenciones habituales de Laravel: nombrado de modelos, herencia de controladores, estructura de middleware, etc.

***

## Ejemplos prácticos en un proyecto Laravel

### Crear tests

```shell theme={null}
php artisan make:test UserTest
```

En Laravel 11 y posteriores, con la configuración por defecto, se genera un archivo de test en formato Pest.

```php theme={null}
<?php

test('example', function () {
    expect(true)->toBeTrue();
});
```

### Usar los helpers de test de Laravel tal cual

Como Pest hereda del `TestCase` de Laravel, puedes usar tal cual todos los helpers de test de Laravel: `actingAs()`, `assertDatabaseHas()`, los helpers de tests HTTP, etc.

```php theme={null}
use App\Models\Post;
use App\Models\User;

test('el usuario puede borrar sus propios posts', function () {
    $user = User::factory()->create();
    $post = Post::factory()->for($user)->create();

    $response = $this
        ->actingAs($user)
        ->delete("/posts/{$post->id}");

    $response->assertRedirect('/posts');
    $this->assertModelMissing($post);
});

test('no se pueden borrar posts de otros usuarios', function () {
    $user = User::factory()->create();
    $otherUser = User::factory()->create();
    $post = Post::factory()->for($otherUser)->create();

    $this
        ->actingAs($user)
        ->delete("/posts/{$post->id}")
        ->assertForbidden();

    $this->assertModelExists($post);
});
```

### Factories y transacciones de base de datos

También puedes aplicar fácilmente los traits `RefreshDatabase` o `DatabaseTransactions` con `uses()`. Si lo pones al principio del archivo, se aplica a todo el archivo.

```php theme={null}
uses(Tests\TestCase::class, Illuminate\Foundation\Testing\RefreshDatabase::class)->in('Feature');
```

Si lo configuras una vez en `tests/Pest.php`, `RefreshDatabase` se activa automáticamente en todos los tests Feature. También se puede sobrescribir en archivos de test individuales.

***

## Cómo convivir con tests PHPUnit existentes

Pest y PHPUnit pueden convivir en el mismo proyecto. No es necesario reescribir los tests PHPUnit existentes; basta con empezar a escribir los tests nuevos en formato Pest.

```shell theme={null}
./vendor/bin/pest       # Ejecuta todos los tests con Pest (incluidos los PHPUnit)
./vendor/bin/pest --filter="usuario"  # Filtra por nombre de test
php artisan test        # Con el comando Artisan también funciona Pest
```

<Info>
  Desde Laravel 11, si Pest está instalado, `php artisan test` ejecuta automáticamente con Pest.
</Info>

### Cómo abordar la migración

1. Primero añade la configuración de `uses()` en `tests/Pest.php`
2. Escribe los nuevos tests en formato Pest
3. Ve migrando los tests PHPUnit existentes poco a poco, comprobando su funcionamiento

No hace falta reescribir todos los tests de golpe. Como la sintaxis de Pest tiene menor coste de aprendizaje que la de PHPUnit, la adopción por parte del equipo es relativamente fluida.

***

## Conclusión

| Elemento de comparación      | PHPUnit            | Pest                                 |
| ---------------------------- | ------------------ | ------------------------------------ |
| Definición de test           | Clase + método     | Funciones `test()` / `it()`          |
| Aserción                     | `$this->assert*()` | `expect()->to*()`                    |
| Setup                        | `setUp()`          | `beforeEach()`                       |
| Data-driven                  | `@dataProvider`    | `->with()`                           |
| Verificación de arquitectura | No                 | `arch()`                             |
| Velocidad de ejecución       | Estándar           | Equivalente (funciona sobre PHPUnit) |

Pest no es un reemplazo de PHPUnit, sino una capa superior que envuelve a PHPUnit. La integración con Laravel también es profunda, hasta el punto de que se selecciona por defecto al generar los starter kits. El coste de introducción en proyectos existentes es bajo, y solo con probar a escribir los nuevos tests con Pest ya obtienes beneficios.

Cuando aumenta la cantidad de tests escritos, se detectan antes los bugs y baja la barrera psicológica para refactorizar. Pest es una herramienta para reducir "la fricción de escribir tests" en sí.

<Card title="Documentación oficial de Pest" icon="book-open" href="https://pestphp.com/docs">
  Para todas las funciones de Pest (datasets, cobertura, ejecución en paralelo, etc.), consulta la documentación oficial.
</Card>


## Related topics

- [Introducción a las pruebas](/es/testing.md)
- [Pruebas avanzadas con Pest](/es/advanced/testing-pest.md)
- [VOICEVOX for Laravel](/es/packages/laravel-voicevox/index.md)
- [Probar paquetes Laravel con Orchestra Testbench](/es/advanced/package-testing.md)
- [Actualización de Laravel 8 a 9](/es/blog/upgrade-8-to-9.md)
