aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Développement Web

Tests Laravel : guide pratique PHPUnit et Pest

Écrire des tests Laravel est l'habitude qui transforme un projet — un tas de code qui « semble fonctionner » — en une base de code que l'on peut modifier en toute confiance. Les tests vous disent instantanément quel comportement un refactor a cassé ; ils servent de documentation vivante pour le prochain développeur ; et surtout, ils retirent l'angoisse du « ai-je cassé quelque chose ? » à chaque déploiement. Dans ce guide, nous couvrirons les deux moteurs de test de Laravel — PHPUnit par défaut et le Pest de plus en plus populaire, à la syntaxe plus épurée — à travers des exemples concrets.

Comment les tests sont configurés dans Laravel

Un projet Laravel neuf est déjà livré avec les tests. Le fichier phpunit.xml à la racine définit l'environnement de test, tandis que le dossier tests/ se divise en deux répertoires : tests/Unit et tests/Feature. La distinction est conceptuelle :

  • Les tests unitaires éprouvent une seule classe ou méthode de façon isolée, sans démarrer tout le framework. Ils sont rapides et se concentrent sur la logique pure (calculs, formatage, petits services).
  • Les tests feature vérifient une requête HTTP, une route, la base de données et plusieurs classes fonctionnant ensemble, de bout en bout. Ce sont eux qui apportent le plus de valeur dans la vraie vie.

La manière la plus pratique de les exécuter est le wrapper de Laravel :

php artisan test
# ou directement :
./vendor/bin/phpunit
# pour filtrer un seul test :
php artisan test --filter=ProjectCanBeCreated

Dans phpunit.xml, l'environnement de test est généralement configuré avec APP_ENV=testing et une base SQLite en mémoire (DB_CONNECTION=sqlite, DB_DATABASE=:memory:). Ainsi les tests s'exécutent sur un schéma propre à chaque fois, sans toucher à votre vraie base de données.

Écrire son premier test feature

Artisan suffit pour générer une classe de test :

php artisan make:test ProjectTest          # tests/Feature
php artisan make:test PriceTest --unit      # tests/Unit

Un test feature simple commence par confirmer qu'une page se charge correctement. Avec la syntaxe PHPUnit :

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;

class ProjectTest extends TestCase
{
    use RefreshDatabase;

    public function test_homepage_loads_successfully(): void
    {
        $response = $this->get('/');

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

Ici, $this->get('/') simule une vraie requête HTTP ; assertStatus et assertSee vérifient la réponse. Le nom de la méthode de test doit commencer par test_ (ou être marqué de l'attribut #[Test]) pour que PHPUnit le reconnaisse.

Tests de base de données et RefreshDatabase

Pour les tests qui touchent à la base, le trait RefreshDatabase est essentiel : il réinitialise le schéma dans une transaction avant chaque test puis l'annule ensuite, de sorte que les tests ne se contaminent jamais. Pour produire des données, on utilise des factories :

public function test_project_is_persisted(): void
{
    $project = Project::factory()->create([
        'title' => ['fr' => 'Projet de test'],
    ]);

    $this->assertDatabaseHas('projects', [
        'id' => $project->id,
    ]);
}

assertDatabaseHas interroge directement une ligne. Son pendant assertDatabaseMissing est pratique pour tester les suppressions. Les factories se trouvent dans database/factories et génèrent des données aléatoires réalistes via l'assistant fake().

Authentification, JSON et envoi de formulaires

Dans les applications réelles, la plupart des routes exigent un utilisateur authentifié. Laravel gère cela en une ligne avec actingAs :

public function test_authorised_user_can_add_project(): void
{
    $user = User::factory()->create();

    $response = $this->actingAs($user)->post('/admin/projects', [
        'title_fr' => 'Nouveau projet',
    ]);

    $response->assertRedirect('/admin/projects');
    $this->assertDatabaseHas('projects', ['title->fr' => 'Nouveau projet']);
}

Pour les API JSON, il existe des méthodes comme getJson et postJson, plus des assertions conscientes de la structure telles que assertJson / assertJsonStructure :

$this->getJson('/api/projects')
     ->assertOk()
     ->assertJsonCount(3, 'data')
     ->assertJsonStructure(['data' => [['id', 'title']]]);

Écrire les mêmes tests de façon plus concise avec Pest

Pest est un framework de test construit au-dessus de PHPUnit ; le moteur est identique, la syntaxe plus fluide. Au lieu de classes et de méthodes, on écrit des tests à base de fonctions. Le même test feature ressemble à ceci avec Pest :

<?php

use App\Models\User;

it('permet à un utilisateur autorisé d\'ajouter un projet', function () {
    $user = User::factory()->create();

    $this->actingAs($user)
        ->post('/admin/projects', ['title_fr' => 'Nouveau projet'])
        ->assertRedirect('/admin/projects');

    expect(Project::count())->toBe(1);
});

L'expression expect() offre une chaîne d'assertions lisible (toBe, toBeTrue, toContain…). Les traits comme RefreshDatabase s'appliquent à tout un répertoire d'un coup via uses() dans le fichier tests/Pest.php. Pour installer Pest, ajoutez le paquet pestphp/pest avec Composer et lancez php artisan pest:install ; vos tests PHPUnit existants continuent de fonctionner côte à côte, sans modification.

Simuler les dépendances : mocks et fakes

De bons tests ne se connectent jamais réellement aux services externes (e-mail, paiement, notifications). Laravel fournit des fakes prêts à l'emploi pour cela. Par exemple, vous pouvez vérifier qu'une notification a été envoyée sans expédier un vrai e-mail :

use Illuminate\Support\Facades\Mail;

Mail::fake();

// ... action ...

Mail::assertSent(WelcomeMail::class);

La même idée s'applique à Queue::fake(), Event::fake(), Storage::fake() et Http::fake(). Cela garde les tests rapides et déterministes — ils ne dépendent plus d'une connexion réseau ni de l'état d'un service tiers.

Questions fréquentes

Faut-il choisir PHPUnit ou Pest ?

Les deux utilisent le même moteur, ce n'est donc pas une compétition de supériorité technique. Si vous voulez une structure familière, à base de classes et orientée entreprise, choisissez PHPUnit ; si vous préférez moins de code répétitif et une syntaxe lisible, Pest est pertinent. Pour les nouveaux projets, Pest devient de plus en plus le choix par défaut, mais les habitudes de votre équipe doivent trancher.

Faut-il tout tester ?

Non. Viser 100 % de couverture est généralement contre-productif. Testez d'abord les flux critiques pour le métier (paiement, inscription, autorisation, commandes) et les endroits qui ont déjà cassé. Écrire des tests pour de simples getters/setters ou pour le code du framework est une perte de temps.

Pourquoi mes tests sont-ils lents ?

Les causes les plus fréquentes sont l'utilisation d'une vraie base de données au lieu de SQLite en mémoire, et l'absence de fakes pour les services externes. Avec SQLite :memory:, RefreshDatabase et des fakes appropriés, une suite de tests peut s'exécuter en quelques secondes.

Vous voulez intégrer les tests dans votre projet ? Si vous avez besoin d'aide pour mettre en place une suite de tests fiable sur votre application Laravel existante, jusqu'à l'intégration CI/CD, contactez-moi — renforçons ensemble votre base de code.

Bu kategorideki tüm yazılar →

Devamı için