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

# Iniziare a testare Laravel con Pest PHP

> Presentiamo Pest PHP, diventato l'impostazione predefinita a partire da Laravel 11, dal punto di vista di un ingegnere senior. Spiega, tenendo conto dell'introduzione in progetti reali, differenze rispetto a PHPUnit, costo di migrazione e uso dei test `arch()`.

## Perché Pest è diventato il default di Laravel

Da Laravel 11 in poi, quando crei un progetto con `laravel new`, **Pest** viene selezionato come framework di test predefinito. PHPUnit è stato per anni lo strumento standard per i test PHP, ma Pest si basa su PHPUnit offrendo una scrittura di test più concisa e leggibile.

<Info>
  Pest funziona sopra PHPUnit, quindi i test PHPUnit esistenti si eseguono così come sono. La migrazione può procedere gradualmente.
</Info>

Dietro l'adozione ufficiale di Pest c'è l'obiettivo di ridurre l'attrito nello scrivere test. Eliminando la procedura rituale di definire una classe e scrivere un metodo, e fornendo una scrittura che permette di concentrarsi su "ciò che vogliamo testare", diventa naturale acquisire l'abitudine di scrivere test.

***

## Differenze principali rispetto a PHPUnit

### Scrittura del test

La differenza più evidente è il modo in cui si scrivono i test.

<Tabs>
  <Tab title="Pest">
    ```php theme={null}
    test('l\'utente può effettuare il login', 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 funzione `test()` di Pest riceve una closure. Non serve definire classi o metodi e l'intento del test è chiaro fin dalla prima riga. Si può usare anche `it()`. In inglese si legge come una frase naturale: `it('can login', ...)`.

### API `expect()`

Il tratto distintivo di Pest sono le asserzioni in stile chain con `expect()`.

```php theme={null}
test('l\'API elenco post ritorna 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();
});
```

`expect($value)->toBe()`, `->toBeNull()`, `->toContain()`, `->toHaveCount()` e simili permettono di scrivere asserzioni che si leggono in modo naturale. Puoi anche concatenare più asserzioni.

```php theme={null}
expect($user)
    ->name->toBe('Mario Rossi')
    ->email->toBe('mario@example.com')
    ->is_admin->toBeFalse();
```

### Setup e teardown

Il corrispondente di `setUp()` di PHPUnit è `beforeEach()`, quello di `tearDown()` è `afterEach()`.

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

test('un utente autenticato può accedere al profilo', function () {
    $response = $this->get('/profile');
    $response->assertOk();
});

test('un utente autenticato può aggiornare il profilo', function () {
    $response = $this->patch('/profile', ['name' => 'Nuovo nome']);
    $response->assertRedirect('/profile');
});
```

### Dataset — test table-driven

Se vuoi eseguire la stessa logica di test su più dati, usa `dataset`.

```php theme={null}
test('un indirizzo email non valido causa errore di validazione', function (string $email) {
    $response = $this->postJson('/api/users', [
        'name' => 'Mario Rossi',
        'email' => $email,
    ]);

    $response->assertUnprocessable();
})->with([
    'nessuna email' => [''],
    'formato non valido' => ['notanemail'],
    'doppia @' => ['a@@example.com'],
]);
```

Le label di ciascun dataset (`'nessuna email'`, ecc.) vengono aggiunte al nome del test, così vedi a colpo d'occhio quale caso è fallito.

***

## Test `arch()` — verifica automatica dell'architettura

`arch()` di Pest è un test che verifica la struttura della codebase. Puoi verificare automaticamente regole architetturali come "il controller non dipende direttamente dal modello" o "il modello estende Eloquent".

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

test('i controller sono final', function () {
    arch()->expect('App\Http\Controllers')
        ->toBeFinal();
});

test('le classi service non dipendono dai controller', function () {
    arch()->expect('App\Services')
        ->not->toUse('App\Http\Controllers');
});
```

<Tip>
  I test `arch()` vengono eseguiti effettuando analisi statica del codice sorgente. Non inviano richieste HTTP né accedono al database, quindi sono estremamente veloci.
</Tip>

Pest include anche preset di regole architetturali comunemente usate.

```php theme={null}
test('rispetta le regole di architettura di Laravel', function () {
    arch()->preset()->laravel();
});
```

Il preset `laravel()` verifica insieme regole conformi alle convenzioni tipiche di Laravel come naming dei modelli, ereditarietà dei controller e struttura dei middleware.

***

## Esempi pratici in un progetto Laravel

### Creazione del test

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

Da Laravel 11 in poi, con la configurazione predefinita, viene generato un file di test in formato Pest.

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

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

### Usare gli helper di test di Laravel senza modifiche

Pest eredita il `TestCase` di Laravel, quindi puoi usare così come sono tutti gli helper di test di Laravel come `actingAs()`, `assertDatabaseHas()` e gli helper di test HTTP.

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

test('l\'utente può eliminare i propri post', 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('non si possono eliminare i post di altri utenti', 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);
});
```

### Factory e transazioni database

Anche i trait `RefreshDatabase` o `DatabaseTransactions` si applicano facilmente con `uses()`. Scritto in cima al file si applica all'intero file.

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

Impostandolo una volta in `tests/Pest.php`, `RefreshDatabase` viene abilitato automaticamente per tutti i test Feature. Puoi anche sovrascriverlo nel singolo file di test.

***

## Come convivere con i test PHPUnit esistenti

Pest e PHPUnit possono convivere nello stesso progetto. Non è necessario riscrivere i test PHPUnit esistenti: basta iniziare a scrivere i nuovi test in stile Pest.

```shell theme={null}
./vendor/bin/pest       # Esegui tutti i test con Pest (inclusi quelli PHPUnit)
./vendor/bin/pest --filter="utente"  # Filtra per nome del test
php artisan test        # Anche il comando Artisan usa Pest
```

<Info>
  Da Laravel 11 in poi, `php artisan test` usa automaticamente Pest se installato.
</Info>

### Come procedere con la migrazione

1. Aggiungi prima la configurazione di `uses()` in `tests/Pest.php`
2. Scrivi i nuovi test in stile Pest
3. Migra gradualmente i test PHPUnit esistenti verificando il funzionamento

Non serve riscrivere tutti i test in fretta. La sintassi di Pest ha un costo di apprendimento inferiore rispetto a PHPUnit, quindi anche l'adozione da parte del team è relativamente fluida.

***

## Conclusioni

| Confronto               | PHPUnit            | Pest                          |
| ----------------------- | ------------------ | ----------------------------- |
| Definizione dei test    | Classe + metodo    | Funzione `test()` / `it()`    |
| Asserzioni              | `$this->assert*()` | `expect()->to*()`             |
| Setup                   | `setUp()`          | `beforeEach()`                |
| Data-driven             | `@dataProvider`    | `->with()`                    |
| Verifica architetturale | Assente            | `arch()`                      |
| Velocità di esecuzione  | Standard           | Equivalente (gira su PHPUnit) |

Pest non è una sostituzione di PHPUnit, ma un layer superiore che lo avvolge. Ha un'integrazione profonda con Laravel, al punto da essere selezionato di default dallo starter kit. Il costo di introduzione nei progetti esistenti è basso e basta iniziare dai nuovi test per beneficiarne.

Aumentando la quantità di test scritti, si scoprono prima i bug e cala la barriera psicologica verso il refactoring. Pest è lo strumento che riduce "l'attrito stesso dello scrivere test".

<Card title="Documentazione ufficiale di Pest" icon="book-open" href="https://pestphp.com/docs">
  Per tutte le funzionalità di Pest come dataset, coverage ed esecuzione parallela, consulta la documentazione ufficiale.
</Card>


## Related topics

- [Test avanzati con Pest](/it/advanced/testing-pest.md)
- [Conoscenze necessarie prima di iniziare con Laravel](/it/true-tutorial.md)
- [Testare pacchetti Laravel con Orchestra Testbench](/it/advanced/package-testing.md)
- [Installazione](/it/installation.md)
- [Analisi statica dei pacchetti (PHPStan / Larastan)](/it/advanced/package-static-analysis.md)
