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

# Se lancer dans les tests Laravel avec Pest PHP

> Présentation, du point de vue d'un ingénieur senior, de Pest PHP devenu la valeur par défaut à partir de Laravel 11. Différences avec PHPUnit, coût de migration, utilisation des tests `arch()` — l'article traite la mise en place concrète en projet.

## Pourquoi Pest est devenu la valeur par défaut de Laravel

À partir de Laravel 11, quand vous créez un projet avec `laravel new`, **Pest** est sélectionné comme framework de test par défaut. PHPUnit est utilisé depuis longtemps comme outil de test standard en PHP, mais Pest s'appuie sur PHPUnit tout en offrant une écriture de tests plus concise et lisible.

<Info>
  Pest s'exécute au-dessus de PHPUnit, si bien que les tests PHPUnit existants tournent tels quels. La migration peut se faire progressivement.
</Info>

Derrière l'adoption officielle de Pest se cache un objectif : réduire les frictions d'écriture des tests. En supprimant le rituel « définir une classe, écrire une méthode », en fournissant une écriture qui met l'accent sur « ce qu'on veut tester », on incite naturellement à en écrire davantage.

***

## Principales différences avec PHPUnit

### Syntaxe des tests

La différence la plus évidente est la manière d'écrire un test.

<Tabs>
  <Tab title="Pest">
    ```php theme={null}
    test('un utilisateur peut se connecter', 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 fonction `test()` de Pest accepte une closure. Aucune classe ni méthode à définir : l'intention est claire dès la première ligne. `it()` s'utilise de la même manière — `it('can login', ...)` se lit comme une phrase anglaise.

### API `expect()`

Le point le plus emblématique de Pest est l'assertion en chaînage via `expect()`.

```php theme={null}
test('l’API de liste des articles renvoie du 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()` — les assertions se lisent naturellement. Vous pouvez chaîner plusieurs assertions.

```php theme={null}
expect($user)
    ->name->toBe('Tarō Tanaka')
    ->email->toBe('tanaka@example.com')
    ->is_admin->toBeFalse();
```

### Setup et teardown

L'équivalent de `setUp()` en PHPUnit est `beforeEach()` ; celui de `tearDown()` est `afterEach()`.

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

test('un utilisateur authentifié peut accéder à son profil', function () {
    $response = $this->get('/profile');
    $response->assertOk();
});

test('un utilisateur authentifié peut mettre à jour son profil', function () {
    $response = $this->patch('/profile', ['name' => 'Nouveau nom']);
    $response->assertRedirect('/profile');
});
```

### Datasets — tests table-driven

Pour rejouer la même logique de test avec plusieurs jeux de données, utilisez `dataset`.

```php theme={null}
test('une adresse e-mail invalide provoque une erreur de validation', function (string $email) {
    $response = $this->postJson('/api/users', [
        'name' => 'Tarō Tanaka',
        'email' => $email,
    ]);

    $response->assertUnprocessable();
})->with([
    'email absent' => [''],
    'format invalide' => ['notanemail'],
    'double @' => ['a@@example.com'],
]);
```

Chaque libellé de dataset (`'email absent'`, etc.) est ajouté au nom du test, permettant de voir en un coup d'œil quel cas a échoué.

***

## Tests `arch()` — vérification automatique de l'architecture

`arch()` de Pest vérifie la structure du code. Vous pouvez faire respecter automatiquement des règles telles que « les contrôleurs ne dépendent pas directement des modèles » ou « les modèles étendent Eloquent ».

```php theme={null}
test('les modèles étendent Eloquent', function () {
    arch()->expect('App\Models')
        ->toExtend(Illuminate\Database\Eloquent\Model::class);
});

test('les contrôleurs sont déclarés final', function () {
    arch()->expect('App\Http\Controllers')
        ->toBeFinal();
});

test('les services ne dépendent pas des contrôleurs', function () {
    arch()->expect('App\Services')
        ->not->toUse('App\Http\Controllers');
});
```

<Tip>
  Les tests `arch()` analysent statiquement le code : ils n'envoient aucune requête HTTP et n'accèdent pas à la base. Ils sont donc extrêmement rapides.
</Tip>

Pest fournit également des préréglages de règles d'architecture courantes.

```php theme={null}
test('respecte les règles d’architecture Laravel', function () {
    arch()->preset()->laravel();
});
```

Le preset `laravel()` regroupe les règles alignées sur les conventions Laravel : nommage des modèles, héritage des contrôleurs, structure des middlewares, etc.

***

## Exemple concret dans un projet Laravel

### Créer un test

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

Depuis Laravel 11, avec la configuration par défaut, un fichier de test au format Pest est généré.

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

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

### Utiliser directement les helpers de test Laravel

Pest étend le `TestCase` Laravel : `actingAs()`, `assertDatabaseHas()`, les helpers HTTP, etc. sont tous disponibles.

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

test('un utilisateur peut supprimer son propre article', 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('un utilisateur ne peut pas supprimer l’article d’un autre', 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 et transactions de base

Les traits `RefreshDatabase` et `DatabaseTransactions` s'appliquent facilement avec `uses()`. Écrit en tête de fichier, cela s'applique au fichier entier.

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

Configuré une fois dans `tests/Pest.php`, `RefreshDatabase` est activé automatiquement pour tous les tests Feature. Chaque fichier peut le surcharger si nécessaire.

***

## Cohabitation avec les tests PHPUnit existants

Pest et PHPUnit cohabitent au sein d'un même projet. Il n'y a rien à réécrire ; il suffit d'écrire les nouveaux tests en style Pest.

```shell theme={null}
./vendor/bin/pest       # Exécute tous les tests avec Pest (y compris les PHPUnit)
./vendor/bin/pest --filter="utilisateur"  # Filtrer par nom de test
php artisan test        # La commande Artisan utilise également Pest
```

<Info>
  Depuis Laravel 11, si Pest est installé, `php artisan test` l'utilise automatiquement.
</Info>

### Étapes de migration

1. Ajouter la configuration `uses()` dans `tests/Pest.php`
2. Écrire les nouveaux tests en style Pest
3. Migrer progressivement les tests PHPUnit existants en vérifiant qu'ils passent

Pas besoin de tout réécrire d'un coup. Le coût d'apprentissage de la syntaxe Pest étant faible par rapport à PHPUnit, l'adoption par l'équipe se fait en douceur.

***

## Conclusion

| Critère                     | PHPUnit            | Pest                           |
| --------------------------- | ------------------ | ------------------------------ |
| Définition d'un test        | Classe + méthode   | Fonction `test()` / `it()`     |
| Assertions                  | `$this->assert*()` | `expect()->to*()`              |
| Setup                       | `setUp()`          | `beforeEach()`                 |
| Data-driven                 | `@dataProvider`    | `->with()`                     |
| Vérification d'architecture | Aucune             | `arch()`                       |
| Vitesse d'exécution         | Standard           | Équivalente (basé sur PHPUnit) |

Pest n'est pas un remplaçant de PHPUnit : c'est une couche supérieure qui l'enveloppe. Son intégration à Laravel est profonde, au point d'être choisi par défaut à la génération d'un starter kit. Le coût d'introduction dans un projet existant est faible ; commencer par les nouveaux tests suffit à récolter les bénéfices.

Écrire plus de tests, c'est trouver plus tôt les bugs et abaisser la barrière psychologique du refactor. Pest est un outil qui vise à réduire précisément « la friction de l'acte d'écrire un test ».

<Card title="Documentation officielle Pest" icon="book-open" href="https://pestphp.com/docs">
  Datasets, couverture, exécution parallèle, etc. : consultez la documentation officielle pour toutes les fonctionnalités de Pest.
</Card>


## Related topics

- [Tests avancés avec Pest](/fr/advanced/testing-pest.md)
- [Tests de navigateur (Dusk)](/fr/dusk.md)
- [Factories Eloquent](/fr/eloquent-factories.md)
- [Développer un package avec Testbench Workbench](/fr/advanced/package-workbench.md)
- [Introduction aux tests](/fr/testing.md)
