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.
Pest s’exécute au-dessus de PHPUnit, si bien que les tests PHPUnit existants tournent tels quels. La migration peut se faire progressivement.
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.
La différence la plus évidente est la manière d’écrire un test.
Pest
PHPUnit
test('un utilisateur peut se connecter', function () { $user = User::factory()->create(); $response = $this->post('/login', [ 'email' => $user->email, 'password' => 'password', ]); $response->assertRedirect('/dashboard');});
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'); }}
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.
Le point le plus emblématique de Pest est l’assertion en chaînage via expect().
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.
L’équivalent de setUp() en PHPUnit est beforeEach() ; celui de tearDown() est afterEach().
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');});
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 ».
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');});
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.
Pest fournit également des préréglages de règles d’architecture courantes.
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.
Configuré une fois dans tests/Pest.php, RefreshDatabase est activé automatiquement pour tous les tests Feature. Chaque fichier peut le surcharger si nécessaire.
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.
./vendor/bin/pest # Exécute tous les tests avec Pest (y compris les PHPUnit)./vendor/bin/pest --filter="utilisateur" # Filtrer par nom de testphp artisan test # La commande Artisan utilise également Pest
Depuis Laravel 11, si Pest est installé, php artisan test l’utilise automatiquement.
Ajouter la configuration uses() dans tests/Pest.php
Écrire les nouveaux tests en style Pest
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.
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 ».
Documentation officielle Pest
Datasets, couverture, exécution parallèle, etc. : consultez la documentation officielle pour toutes les fonctionnalités de Pest.