Passer au contenu principal

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 comme PHPUnit. Une nouvelle installation contient déjà un fichier phpunit.xml et un répertoire tests/.
Pest est construit sur PHPUnit et propose une syntaxe plus concise et lisible. Si vous débutez, Pest est recommandé.

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.
# 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.
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 :
# 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.
<?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

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);
    }
}

Assertions courantes

PestPHPUnitDescription
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.
<?php

test('la page d\'accueil s\'affiche', function () {
    $response = $this->get('/');

    $response->assertStatus(200);
});
<?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);
    }
}

Exemple : tests HTTP pour une app ToDo

Avec un modèle Todo, testons les opérations CRUD.
<?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

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]);
    }
}

Assertions courantes sur la réponse

MéthodeDescription
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
Le trait RefreshDatabase réinitialise la base après chaque test. Utile pour éviter que les tests interfèrent entre eux.

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.
<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.
<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.
APP_ENV=testing
DB_CONNECTION=sqlite
DB_DATABASE=:memory:
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.

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.
composer require brianium/paratest --dev
Puis exécutez avec --parallel.
php artisan test --parallel
Par défaut, autant de processus que de cœurs CPU sont lancés. Spécifiez le nombre avec --processes.
php artisan test --parallel --processes=4
En parallèle, chaque processus doit utiliser une base isolée. La combinaison RefreshDatabase + SQLite en mémoire via phpunit.xml fonctionne parfaitement.

Prochaines étapes

Tests HTTP

Simulez des requêtes, testez avec authentification, faites des assertions JSON…
Dernière modification le 13 juillet 2026