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

# Introduction aux tests

> Comment écrire des tests pour une application Laravel avec Pest et PHPUnit.

## Qu'est-ce que les tests

Les tests sont un mécanisme automatisé pour vérifier que le code fonctionne comme prévu.
En écrivant des tests, vous pouvez rapidement vérifier que les modifications ou les ajouts n'ont pas cassé les comportements existants.
Ils permettent aussi à toute l'équipe de modifier et de revoir le code avec sérénité.

Laravel intègre le support des tests dès l'installation, et vous pouvez utiliser [Pest](https://pestphp.com) comme [PHPUnit](https://phpunit.de).
Une nouvelle installation contient déjà un fichier `phpunit.xml` et un répertoire `tests/`.

<Tip>
  Pest est construit sur PHPUnit et propose une syntaxe plus concise et lisible. Si vous débutez, Pest est recommandé.
</Tip>

## Structure du répertoire `tests/`

```
tests/
├── Feature/      # Tests fonctionnels
│   └── ExampleTest.php
├── Unit/         # Tests unitaires
│   └── ExampleTest.php
└── TestCase.php
```

* **`Feature/`** — Contient les tests fonctionnels, qui simulent des requêtes HTTP et couvrent de larges parties du système : plusieurs objets qui collaborent, endpoints d'API. **La plupart de vos tests iront ici.**
* **`Unit/`** — Contient les tests unitaires, ciblant une classe ou une méthode. L'application Laravel n'est pas amorcée : pas d'accès à la base ni aux fonctionnalités du framework.

## Créer un test

Utilisez `make:test`.

```shell theme={null}
# Test fonctionnel (par défaut)
php artisan make:test TodoTest

# Test unitaire
php artisan make:test TodoTest --unit
```

`tests/Feature/TodoTest.php` est généré.

## Exécuter les tests

Utilisez `php artisan test`.

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

`vendor/bin/pest` ou `vendor/bin/phpunit` donnent le même résultat, mais `php artisan test` offre une sortie plus lisible.

Pour cibler une suite ou d'autres options :

```shell theme={null}
# Uniquement les Feature tests
php artisan test --testsuite=Feature

# Arrêt au premier échec
php artisan test --stop-on-failure
```

## Écrire un test simple

Exemples d'assertions basiques.

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

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

  test('la chaîne contient un mot', 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>

### Assertions courantes

| Pest                          | PHPUnit                                     | Description                  |
| ----------------------------- | ------------------------------------------- | ---------------------------- |
| `expect($x)->toBe($y)`        | `$this->assertSame($y, $x)`                 | Strictement égal             |
| `expect($x)->toEqual($y)`     | `$this->assertEquals($y, $x)`               | Égal sans considérer le type |
| `expect($x)->toBeTrue()`      | `$this->assertTrue($x)`                     | Est `true`                   |
| `expect($x)->toBeFalse()`     | `$this->assertFalse($x)`                    | Est `false`                  |
| `expect($x)->toBeNull()`      | `$this->assertNull($x)`                     | Est `null`                   |
| `expect($x)->toContain($y)`   | `$this->assertStringContainsString($y, $x)` | Contient une sous-chaîne     |
| `expect($x)->toHaveCount($n)` | `$this->assertCount($n, $x)`                | Nombre d'éléments            |

## Tests HTTP

Les tests HTTP de Laravel simulent les requêtes vers les routes sans démarrer un vrai serveur.
Une fonctionnalité puissante à utiliser dans les tests de `Feature/`.

### Tester l'affichage d'une page

`get()` envoie une requête GET, puis on vérifie la réponse.

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

  test('la page d\'accueil s\'affiche', 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>

### Exemple : tests HTTP pour une app ToDo

Avec un modèle `Todo`, testons les opérations CRUD.

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

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

  uses(RefreshDatabase::class);

  test('la liste des ToDo s\'affiche', function () {
      Todo::factory()->count(3)->create();

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

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

  test('un ToDo peut être créé', function () {
      $response = $this->post('/todos', [
          'title' => 'Apprendre Laravel',
      ]);

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

  test('un ToDo peut être supprimé', 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('Liste');
      }

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

          $response->assertRedirect('/todos');
          $this->assertDatabaseHas('todos', ['title' => 'Apprendre 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>

### Assertions courantes sur la réponse

| Méthode                                 | Description                                   |
| --------------------------------------- | --------------------------------------------- |
| `assertStatus(200)`                     | Vérifie le code HTTP                          |
| `assertOk()`                            | Vérifie que le statut est 200                 |
| `assertRedirect('/path')`               | Vérifie la redirection                        |
| `assertSee('texte')`                    | Vérifie que le texte apparaît dans la réponse |
| `assertDontSee('texte')`                | Vérifie que le texte n'apparaît pas           |
| `assertJson([...])`                     | Vérifie une réponse JSON                      |
| `assertDatabaseHas('table', [...])`     | Vérifie la présence d'un enregistrement       |
| `assertDatabaseMissing('table', [...])` | Vérifie l'absence d'un enregistrement         |

<Info>
  Le trait `RefreshDatabase` réinitialise la base après chaque test. Utile pour éviter que les tests interfèrent entre eux.
</Info>

## Environnement de test

### Configuration `phpunit.xml`

`phpunit.xml` à la racine configure l'environnement de test.
Par défaut, session et cache utilisent le driver `array`, donc rien n'est persisté pendant les tests.

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

Pour la base, il est courant d'utiliser SQLite en mémoire.

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

### Fichier `.env.testing`

Un fichier `.env.testing` à la racine remplace `.env` pendant les tests.
Utile pour isoler la base ou les services externes utilisés en test.

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

<Warning>
  Si vous avez mis en cache la configuration, exécutez `php artisan config:clear` avant les tests. Sinon, l'ancienne configuration peut être utilisée.
</Warning>

## Exécution parallèle

Quand le nombre de tests augmente, le temps d'exécution grandit.
L'option `--parallel` lance plusieurs processus en parallèle pour réduire ce temps.

Installez d'abord le package `brianium/paratest`.

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

Puis exécutez avec `--parallel`.

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

Par défaut, autant de processus que de cœurs CPU sont lancés. Spécifiez le nombre avec `--processes`.

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

<Tip>
  En parallèle, chaque processus doit utiliser une base isolée. La combinaison `RefreshDatabase` + SQLite en mémoire via `phpunit.xml` fonctionne parfaitement.
</Tip>

## Prochaines étapes

<Card title="Tests HTTP" icon="arrow-right" href="/fr/http-tests">
  Simulez des requêtes, testez avec authentification, faites des assertions JSON…
</Card>


## Related topics

- [Tests avancés avec Pest](/fr/advanced/testing-pest.md)
- [Factories Eloquent](/fr/eloquent-factories.md)
- [Introduction aux relations Eloquent](/fr/eloquent-relationships.md)
- [Introduction à l'authentification](/fr/authentication.md)
- [Introduction à Laravel Nightwatch](/fr/blog/nightwatch-introduction.md)
