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

# Test HTTP

> Simulazione di richieste, asserzioni, test di autenticazione e upload file usando le funzionalità di test HTTP di Laravel

## Introduzione

Laravel offre un'API ricca per simulare richieste HTTP e verificarne le risposte.
Puoi riprodurre nei test le richieste all'applicazione senza avviare un vero server HTTP.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('l\'applicazione restituisce una risposta corretta', function () {
      $response = $this->get('/');

      $response->assertStatus(200);
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_the_application_returns_a_successful_response(): void
      {
          $response = $this->get('/');

          $response->assertStatus(200);
      }
  }
  ```
</CodeGroup>

Il metodo `get()` invia una richiesta `GET` all'applicazione e `assertStatus()` verifica il codice HTTP.

<Info>
  Durante l'esecuzione dei test il middleware CSRF è disabilitato automaticamente. Non è necessario disabilitarlo esplicitamente.
</Info>

## Effettuare richieste

Nei test puoi usare i metodi `get`, `post`, `put`, `patch`, `delete`.
Non fanno vere richieste di rete, ma simulano internamente. Restituiscono un'istanza di `Illuminate\Testing\TestResponse` con molti metodi di asserzione.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  test('richiesta di base', function () {
      $response = $this->get('/');

      $response->assertStatus(200);
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_a_basic_request(): void
      {
          $response = $this->get('/');

          $response->assertStatus(200);
      }
  }
  ```
</CodeGroup>

<Warning>
  In un test consigliamo di inviare una sola richiesta. Più richieste nello stesso test possono generare comportamenti inattesi.
</Warning>

### Header di richiesta

Con `withHeaders()` personalizzi gli header.

```php theme={null}
$response = $this->withHeaders([
    'X-Header' => 'Value',
])->post('/user', ['name' => 'Sally']);

$response->assertStatus(201);
```

### Cookie

Con `withCookie()` o `withCookies()`.

```php theme={null}
$response = $this->withCookie('color', 'blue')->get('/');

$response = $this->withCookies([
    'color' => 'blue',
    'name'  => 'Taylor',
])->get('/');
```

### Sessione e autenticazione

Con `withSession()` imposti dati di sessione.

```php theme={null}
$response = $this->withSession(['banned' => false])->get('/');
```

Con `actingAs()` esegui come utente autenticato.

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

$user = User::factory()->create();

$response = $this->actingAs($user)
    ->withSession(['banned' => false])
    ->get('/');
```

Puoi indicare la guard nel secondo argomento.

```php theme={null}
$this->actingAs($user, 'web');
```

Per richieste da non autenticato:

```php theme={null}
$this->actingAsGuest();
```

### Debug delle risposte

```php theme={null}
$response->dump();
$response->dumpHeaders();
$response->dumpSession();

$response->dd();
$response->ddHeaders();
$response->ddBody();
$response->ddJson();
$response->ddSession();
```

### Test delle eccezioni

Con la facade `Exceptions`.

```php theme={null}
use App\Exceptions\InvalidOrderException;
use Illuminate\Support\Facades\Exceptions;

Exceptions::fake();

$response = $this->get('/order/1');

Exceptions::assertReported(InvalidOrderException::class);

Exceptions::assertReported(function (InvalidOrderException $e) {
    return $e->getMessage() === 'The order was invalid.';
});
```

Per verificare che non siano state emesse eccezioni:

```php theme={null}
Exceptions::assertNotReported(InvalidOrderException::class);
Exceptions::assertNothingReported();
```

Per disabilitare la gestione delle eccezioni:

```php theme={null}
$response = $this->withoutExceptionHandling()->get('/');
```

Per testare eccezioni lanciate da closure:

```php theme={null}
$this->assertThrows(
    fn () => (new ProcessOrder)->execute(),
    OrderInvalid::class
);

$this->assertThrows(
    fn () => (new ProcessOrder)->execute(),
    fn (OrderInvalid $e) => $e->orderId() === 123
);

$this->assertDoesntThrow(fn () => (new ProcessOrder)->execute());
```

## Test di API JSON

Laravel offre helper per JSON: `json`, `getJson`, `postJson`, `putJson`, `patchJson`, `deleteJson`, `optionsJson`.

```php theme={null}
$response = $this->postJson('/api/user', ['name' => 'Sally']);

$response
    ->assertStatus(201)
    ->assertJson([
        'created' => true,
    ]);
```

Puoi accedere ai dati JSON come array:

```php theme={null}
expect($response['created'])->toBeTrue();
```

<Info>
  `assertJson()` verifica che i dati indicati siano *contenuti* nella risposta JSON. Il test passa anche se la risposta ha proprietà aggiuntive.
</Info>

### Corrispondenza esatta

```php theme={null}
$response
    ->assertStatus(201)
    ->assertExactJson([
        'created' => true,
    ]);
```

### JSON path

```php theme={null}
$response
    ->assertStatus(201)
    ->assertJsonPath('team.owner.name', 'Darian');

// Con closure
$response->assertJsonPath('team.owner.name', fn (string $name) => strlen($name) >= 3);
```

### Test JSON fluente

```php theme={null}
use Illuminate\Testing\Fluent\AssertableJson;

$response = $this->getJson('/users/1');

$response
    ->assertJson(fn (AssertableJson $json) =>
        $json->where('id', 1)
            ->where('name', 'Victoria Faith')
            ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com'))
            ->whereNot('status', 'pending')
            ->missing('password')
            ->etc()
    );
```

<Tip>
  `etc()` permette la presenza di proprietà non asserite. Senza `etc()`, se ci sono proprietà non asserite il test fallisce, aiutando a prevenire fughe di dati sensibili nella response.
</Tip>

Per verificare presenza/assenza:

```php theme={null}
$response->assertJson(fn (AssertableJson $json) =>
    $json->has('data')
        ->missing('message')
);

$response->assertJson(fn (AssertableJson $json) =>
    $json->hasAll(['status', 'data'])
        ->missingAll(['message', 'code'])
);
```

#### Collection JSON

```php theme={null}
$response
    ->assertJson(fn (AssertableJson $json) =>
        $json->has(3)
            ->first(fn (AssertableJson $json) =>
                $json->where('id', 1)
                    ->where('name', 'Victoria Faith')
                    ->missing('password')
                    ->etc()
            )
    );
```

Per applicare la stessa asserzione a ogni item usa `each()`:

```php theme={null}
$response
    ->assertJson(fn (AssertableJson $json) =>
        $json->has(3)
            ->each(fn (AssertableJson $json) =>
                $json->whereType('id', 'integer')
                    ->whereType('name', 'string')
                    ->whereType('email', 'string')
                    ->missing('password')
                    ->etc()
            )
    );
```

#### Type assertion

```php theme={null}
$response->assertJson(fn (AssertableJson $json) =>
    $json->whereType('id', 'integer')
        ->whereAllType([
            'users.0.name' => 'string',
            'meta' => 'array'
        ])
);

// Più tipi separati da |
$response->assertJson(fn (AssertableJson $json) =>
    $json->whereType('name', 'string|null')
        ->whereType('id', ['string', 'integer'])
);
```

Tipi: `string`, `integer`, `double`, `boolean`, `array`, `null`.

## Test di autenticazione

```php theme={null}
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('l\'utente autenticato può vedere la dashboard', function () {
    $user = User::factory()->create();

    $response = $this->actingAs($user)->get('/dashboard');

    $response->assertStatus(200);
});

test('l\'utente non autenticato viene reindirizzato', function () {
    $response = $this->get('/dashboard');

    $response->assertRedirect('/login');
});
```

Con guard specifica:

```php theme={null}
$this->actingAs($user, 'api');
```

### Esempio: registrazione utente

```php theme={null}
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('l\'utente può registrarsi', function () {
    $response = $this->post('/register', [
        'name'                  => 'Test User',
        'email'                 => 'test@example.com',
        'password'              => 'password',
        'password_confirmation' => 'password',
    ]);

    $response->assertRedirect('/dashboard');
    $this->assertDatabaseHas('users', ['email' => 'test@example.com']);
});

test('email duplicata non registrabile', function () {
    User::factory()->create(['email' => 'test@example.com']);

    $response = $this->post('/register', [
        'name'                  => 'Test User',
        'email'                 => 'test@example.com',
        'password'              => 'password',
        'password_confirmation' => 'password',
    ]);

    $response->assertSessionHasErrors('email');
});
```

## Test di sessione

```php theme={null}
$response = $this->withSession(['locale' => 'it'])->get('/');

$response->assertSessionHas('locale', 'it');
```

### Elenco delle asserzioni di sessione

| Metodo                                  | Descrizione                      |
| --------------------------------------- | -------------------------------- |
| `assertSessionHas($key, $value)`        | Chiave e valore in sessione      |
| `assertSessionHasAll([...])`            | Più chiavi in sessione           |
| `assertSessionHasErrors($keys)`         | Errori di validazione presenti   |
| `assertSessionHasErrorsIn($bag, $keys)` | Errori in un error bag specifico |
| `assertSessionHasNoErrors()`            | Nessun errore                    |
| `assertSessionDoesntHaveErrors()`       | Nessun errore                    |
| `assertSessionMissing($key)`            | Chiave assente                   |

## Test di upload file

Con `UploadedFile::fake()` e `Storage::fake()`.

```php theme={null}
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;

test('è possibile caricare l\'avatar', function () {
    Storage::fake('avatars');

    $file = UploadedFile::fake()->image('avatar.jpg');

    $response = $this->post('/avatar', [
        'avatar' => $file,
    ]);

    Storage::disk('avatars')->assertExists($file->hashName());
});
```

Per verificare l'assenza:

```php theme={null}
Storage::disk('avatars')->assertMissing('missing.jpg');
```

### Personalizzare i file finti

```php theme={null}
UploadedFile::fake()->image('avatar.jpg', $width, $height)->size(100);

UploadedFile::fake()->create('document.pdf', $sizeInKilobytes);

UploadedFile::fake()->create(
    'document.pdf', $sizeInKilobytes, 'application/pdf'
);
```

## Test di viste

Senza simulare la richiesta HTTP puoi renderizzare direttamente la vista.

```php theme={null}
$view = $this->view('welcome', ['name' => 'Taylor']);

$view->assertSee('Taylor');
```

`TestView` fornisce:

| Metodo                        | Descrizione                |
| ----------------------------- | -------------------------- |
| `assertSee($value)`           | La stringa è presente      |
| `assertSeeInOrder([...])`     | Le stringhe sono in ordine |
| `assertSeeText($value)`       | Il testo è presente        |
| `assertSeeTextInOrder([...])` | I testi sono in ordine     |
| `assertDontSee($value)`       | Non presente               |
| `assertDontSeeText($value)`   | Testo non presente         |

Contenuto come stringa:

```php theme={null}
$contents = (string) $this->view('welcome');
```

Errori di validazione in una vista:

```php theme={null}
$view = $this->withViewErrors([
    'name' => ['Inserisci un nome valido.']
])->view('form');

$view->assertSee('Inserisci un nome valido.');
```

### Test di componenti

```php theme={null}
$view = $this->blade(
    '<x-component :name="$name" />',
    ['name' => 'Taylor']
);

$view->assertSee('Taylor');

$view = $this->component(Profile::class, ['name' => 'Taylor']);

$view->assertSee('Taylor');
```

## Elenco delle asserzioni sulle response

Metodi principali della classe `Illuminate\Testing\TestResponse`.

### Status HTTP

| Metodo                           | Descrizione      |
| -------------------------------- | ---------------- |
| `assertOk()`                     | 200              |
| `assertCreated()`                | 201              |
| `assertAccepted()`               | 202              |
| `assertNoContent($status = 204)` | 204              |
| `assertBadRequest()`             | 400              |
| `assertUnauthorized()`           | 401              |
| `assertForbidden()`              | 403              |
| `assertNotFound()`               | 404              |
| `assertUnprocessable()`          | 422              |
| `assertTooManyRequests()`        | 429              |
| `assertInternalServerError()`    | 500              |
| `assertStatus($code)`            | Status specifico |
| `assertSuccessful()`             | 2xx              |
| `assertClientError()`            | 4xx              |
| `assertServerError()`            | 5xx              |

### Redirect

| Metodo                                        | Descrizione             |
| --------------------------------------------- | ----------------------- |
| `assertRedirect($uri)`                        | Redirect all'URI        |
| `assertRedirectContains($string)`             | URI contiene la stringa |
| `assertRedirectToRoute($name, $params)`       | Alla route con nome     |
| `assertRedirectToSignedRoute($name, $params)` | Alla signed route       |
| `assertRedirectBack()`                        | All'URL precedente      |

### Contenuto

| Metodo                               | Descrizione             |
| ------------------------------------ | ----------------------- |
| `assertSee($value, $escaped = true)` | Presente nella response |
| `assertSeeInOrder(array $values)`    | In ordine               |
| `assertSeeText($value)`              | Testo presente          |
| `assertDontSee($value)`              | Non presente            |
| `assertDontSeeText($value)`          | Testo non presente      |
| `assertContent($value)`              | Body uguale             |
| `assertDownload($filename)`          | È un download           |

### JSON

| Metodo                                     | Descrizione                 |
| ------------------------------------------ | --------------------------- |
| `assertJson(array $data)`                  | Contiene i dati indicati    |
| `assertExactJson(array $data)`             | Corrispondenza esatta       |
| `assertJsonPath($path, $value)`            | Valore al path              |
| `assertJsonMissingPath($path)`             | Path assente                |
| `assertJsonStructure(array $structure)`    | Struttura conforme          |
| `assertJsonCount($count, $key)`            | Numero di elementi          |
| `assertJsonFragment(array $data)`          | Frammento presente          |
| `assertJsonMissing(array $data)`           | Dati assenti                |
| `assertJsonIsArray()`                      | È un array                  |
| `assertJsonIsObject()`                     | È un oggetto                |
| `assertJsonValidationErrors($keys)`        | Errori di validazione       |
| `assertJsonMissingValidationErrors($keys)` | Nessun errore per le chiavi |

### Header e cookie

| Metodo                              | Descrizione        |
| ----------------------------------- | ------------------ |
| `assertHeader($headerName, $value)` | Header presente    |
| `assertHeaderMissing($headerName)`  | Header assente     |
| `assertCookie($name, $value)`       | Cookie presente    |
| `assertCookieExpired($name)`        | Cookie scaduto     |
| `assertCookieMissing($name)`        | Cookie assente     |
| `assertPlainCookie($name, $value)`  | Cookie non cifrato |

### Viste

| Metodo                          | Descrizione      |
| ------------------------------- | ---------------- |
| `assertViewIs($value)`          | Vista restituita |
| `assertViewHas($key, $value)`   | Dati nella vista |
| `assertViewHasAll(array $data)` | Più dati         |
| `assertViewMissing($key)`       | Dato assente     |

### Validazione

| Metodo                 | Descrizione                 |
| ---------------------- | --------------------------- |
| `assertValid($keys)`   | Nessun errore per le chiavi |
| `assertInvalid($keys)` | Errori per le chiavi        |

## Consigli per il TDD

<Tip>
  I test HTTP si sposano bene con il TDD. Consigli:
</Tip>

<AccordionGroup>
  <Accordion title="Parti dai feature test">
    Metti i test HTTP in `tests/Feature/`. Descrivere il comportamento dall'esterno (richiesta → risposta) chiarisce cosa implementare.
  </Accordion>

  <Accordion title="Usa RefreshDatabase">
    Nei test che usano il DB usa il trait `RefreshDatabase`. Il DB viene resettato dopo ogni test evitando interferenze.
  </Accordion>

  <Accordion title="Sfrutta le factory">
    Con `User::factory()->create()` crei rapidamente dati di test. Definisci gli stati (state) per test più leggibili.
  </Accordion>

  <Accordion title="1 test, 1 asserzione">
    Verifica una cosa per test per identificare più facilmente la causa dei fallimenti. Segui lo schema AAA (Arrange, Act, Assert).
  </Accordion>

  <Accordion title="Non dimenticare i test di autenticazione">
    Per le route protette scrivi sempre sia il caso "autenticato" sia "non autenticato". Prevengono problemi di sicurezza.
  </Accordion>
</AccordionGroup>

## Pagine correlate

<Card title="Introduzione al testing" icon="flask" href="/it/testing">
  Le basi dei test in Laravel e l'uso di `php artisan test`.
</Card>


## Related topics

- [Introduzione al testing](/it/testing.md)
- [Iniziare a testare Laravel con Pest PHP](/it/blog/pest-introduction.md)
- [Mock](/it/mocking.md)
- [Test avanzati con Pest](/it/advanced/testing-pest.md)
- [Guida allo sviluppo di app con l'API del motore - VOICEVOX for Laravel](/it/packages/laravel-voicevox/app-guide.md)
