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

# Introduzione al testing

> Come scrivere test per applicazioni Laravel usando Pest e PHPUnit

## Cos'è il testing

Il testing è il meccanismo che verifica automaticamente che il codice funzioni come previsto.
Scrivere test ti permette di verificare rapidamente che aggiungere o modificare funzionalità non rompa il comportamento esistente.
Nello sviluppo in team i test danno sicurezza nel modificare il codice e nelle code review.

Laravel supporta il testing fin dall'inizio: puoi usare sia [Pest](https://pestphp.com) sia [PHPUnit](https://phpunit.de).
Alla creazione del progetto trovi automaticamente il file `phpunit.xml` e la directory `tests/`.

<Tip>
  Pest è costruito su PHPUnit e permette di scrivere test con una sintassi più concisa e leggibile. Se inizi ora, ti consigliamo Pest.
</Tip>

## Struttura della directory `tests/`

```
tests/
├── Feature/      # Feature test
│   └── ExampleTest.php
├── Unit/         # Unit test
│   └── ExampleTest.php
└── TestCase.php
```

* **`Feature/`** — Feature test: test di grande granularità che includono richieste HTTP. Verificano il funzionamento di più oggetti insieme o endpoint API, quindi test più vicini all'applicazione completa. **La maggior parte dei test starà qui.**
* **`Unit/`** — Unit test: test di piccola granularità per singola classe o metodo. L'applicazione Laravel non viene avviata, quindi non puoi usare database o altre funzionalità del framework.

## Creazione di un test

Con il comando Artisan `make:test` generi una nuova classe di test.

```shell theme={null}
# Crea un Feature test (default)
php artisan make:test TodoTest

# Crea uno Unit test
php artisan make:test TodoTest --unit
```

Viene generato `tests/Feature/TodoTest.php`.

## Esecuzione dei test

Esegui i test con il comando `php artisan test`.

```shell theme={null}
php artisan test
```

Puoi eseguire direttamente `vendor/bin/pest` o `vendor/bin/phpunit` per lo stesso risultato, ma `php artisan test` mostra un output più leggibile ed è consigliato.

Per eseguire solo una suite:

```shell theme={null}
# Esegui solo i Feature test
php artisan test --testsuite=Feature

# Fermati al primo fallimento
php artisan test --stop-on-failure
```

## Come scrivere test base

Esempio di asserzioni semplici.

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

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

  test('verifica che la stringa contenga', function () {
      $message = 'Hello, Laravel!';

      expect($message)->toContain('Laravel');
  });
  ```

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

  namespace Tests\Unit;

  use PHPUnit\Framework\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_true_is_true(): void
      {
          $this->assertTrue(true);
      }

      public function test_string_contains_laravel(): void
      {
          $message = 'Hello, Laravel!';

          $this->assertStringContainsString('Laravel', $message);
      }
  }
  ```
</CodeGroup>

### Asserzioni più comuni

| Pest                          | PHPUnit                                     | Descrizione                 |
| ----------------------------- | ------------------------------------------- | --------------------------- |
| `expect($x)->toBe($y)`        | `$this->assertSame($y, $x)`                 | Uguali in senso stretto     |
| `expect($x)->toEqual($y)`     | `$this->assertEquals($y, $x)`               | Uguali (ignora il tipo)     |
| `expect($x)->toBeTrue()`      | `$this->assertTrue($x)`                     | È `true`                    |
| `expect($x)->toBeFalse()`     | `$this->assertFalse($x)`                    | È `false`                   |
| `expect($x)->toBeNull()`      | `$this->assertNull($x)`                     | È `null`                    |
| `expect($x)->toContain($y)`   | `$this->assertStringContainsString($y, $x)` | Contiene la stringa         |
| `expect($x)->toHaveCount($n)` | `$this->assertCount($n, $x)`                | Numero di elementi corretto |

## Test HTTP

Con i test HTTP di Laravel puoi simulare richieste alle route senza avviare un vero server HTTP.
È una funzionalità potente delle classi di test nella directory `Feature/`.

### Verifica della visualizzazione di una pagina

Con `get()` invii una richiesta GET e verifichi la response.

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

  test('la pagina principale viene mostrata', 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_top_page_is_displayed(): void
      {
          $response = $this->get('/');

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

### Esempio di test HTTP di un'app ToDo

Con un'app che ha il modello `Todo`, testiamo le operazioni CRUD.

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

  use App\Models\Todo;
  use Illuminate\Foundation\Testing\RefreshDatabase;

  uses(RefreshDatabase::class);

  test('viene mostrato l\'elenco dei ToDo', function () {
      Todo::factory()->count(3)->create();

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

      $response->assertStatus(200);
      $response->assertSee('Elenco');
  });

  test('è possibile creare un ToDo', function () {
      $response = $this->post('/todos', [
          'title' => 'Studiare Laravel',
      ]);

      $response->assertRedirect('/todos');
      $this->assertDatabaseHas('todos', ['title' => 'Studiare Laravel']);
  });

  test('è possibile eliminare un ToDo', function () {
      $todo = Todo::factory()->create();

      $response = $this->delete("/todos/{$todo->id}");

      $response->assertRedirect('/todos');
      $this->assertDatabaseMissing('todos', ['id' => $todo->id]);
  });
  ```

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

  namespace Tests\Feature;

  use App\Models\Todo;
  use Illuminate\Foundation\Testing\RefreshDatabase;
  use Tests\TestCase;

  class TodoTest extends TestCase
  {
      use RefreshDatabase;

      public function test_todo_list_is_displayed(): void
      {
          Todo::factory()->count(3)->create();

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

          $response->assertStatus(200);
          $response->assertSee('Elenco');
      }

      public function test_todo_can_be_created(): void
      {
          $response = $this->post('/todos', [
              'title' => 'Studiare Laravel',
          ]);

          $response->assertRedirect('/todos');
          $this->assertDatabaseHas('todos', ['title' => 'Studiare Laravel']);
      }

      public function test_todo_can_be_deleted(): void
      {
          $todo = Todo::factory()->create();

          $response = $this->delete("/todos/{$todo->id}");

          $response->assertRedirect('/todos');
          $this->assertDatabaseMissing('todos', ['id' => $todo->id]);
      }
  }
  ```
</CodeGroup>

### Asserzioni comuni sulle response

| Metodo                                  | Descrizione                                            |
| --------------------------------------- | ------------------------------------------------------ |
| `assertStatus(200)`                     | Verifica il codice HTTP della response                 |
| `assertOk()`                            | Verifica che il codice sia 200                         |
| `assertRedirect('/path')`               | Verifica il redirect all'URL                           |
| `assertSee('testo')`                    | Verifica che il corpo della response contenga il testo |
| `assertDontSee('testo')`                | Verifica che il corpo non contenga il testo            |
| `assertJson([...])`                     | Verifica i dati della response JSON                    |
| `assertDatabaseHas('table', [...])`     | Verifica che il record esista nel DB                   |
| `assertDatabaseMissing('table', [...])` | Verifica che il record non esista nel DB               |

<Info>
  Con il trait `RefreshDatabase` il database viene resettato dopo ogni test. Serve a evitare che i dati interferiscano tra i test.
</Info>

## Ambiente di test

### Configurazione di `phpunit.xml`

Configura l'ambiente di test nel file `phpunit.xml` nella root del progetto.
Di default sessione e cache usano il driver `array`, così i dati non permangono tra i test.

```xml theme={null}
<env name="APP_ENV" value="testing"/>
<env name="CACHE_STORE" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
```

Per il database è comune usare SQLite in-memory, che non lascia file.

```xml theme={null}
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
```

### File `.env.testing`

Creando `.env.testing` nella root del progetto, verrà usato al posto di `.env` durante i test.
Utile se vuoi separare connessioni al database o servizi esterni dedicati ai test.

```ini theme={null}
APP_ENV=testing
DB_CONNECTION=sqlite
DB_DATABASE=:memory:
```

<Warning>
  Se hai cache di configurazione, esegui `php artisan config:clear` prima dei test. Altrimenti potrebbe essere usata una cache obsoleta.
</Warning>

## Esecuzione parallela dei test

Con l'aumentare del numero di test cresce anche il tempo di esecuzione.
Con l'opzione `--parallel` esegui i test su più processi contemporaneamente per ridurre i tempi.

Installa prima il pacchetto `brianium/paratest`.

```shell theme={null}
composer require brianium/paratest --dev
```

Esegui con l'opzione `--parallel`.

```shell theme={null}
php artisan test --parallel
```

Di default vengono creati tanti processi quanti sono i core della CPU. Per indicare il numero usa `--processes`.

```shell theme={null}
php artisan test --parallel --processes=4
```

<Tip>
  Con i test paralleli ogni processo deve usare un database indipendente. La combinazione del trait `RefreshDatabase` con SQLite in-memory in `phpunit.xml` funziona senza problemi.
</Tip>

## Prossimi passi

<Card title="Test HTTP" icon="arrow-right" href="/it/http-tests">
  Approfondisci simulazione delle richieste, test autenticati, asserzioni JSON e altri aspetti.
</Card>


## Related topics

- [Test HTTP](/it/http-tests.md)
- [Eloquent Factory](/it/eloquent-factories.md)
- [Introduzione a Eloquent](/it/eloquent.md)
- [Introduzione all'autenticazione](/it/authentication.md)
- [Introduzione a Laravel Nightwatch](/it/blog/nightwatch-introduction.md)
