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

Laravel Testen: praktische gids voor PHPUnit en Pest

Laravel testen schrijven is dé gewoonte die een project — een stapel code die alleen maar “lijkt te werken” — verandert in een codebase die je met vertrouwen kunt aanpassen. Tests vertellen je meteen welk gedrag een refactor heeft gebroken; ze fungeren als levende documentatie voor de volgende ontwikkelaar; en bovenal halen ze de “heb ik iets stukgemaakt?”-spanning uit elke deploy. In deze gids behandelen we de twee testmotoren van Laravel — het standaard PHPUnit en het steeds populairder wordende Pest met zijn strakkere syntaxis — aan de hand van praktische voorbeelden.

Hoe testen in Laravel is opgezet

Een vers Laravel-project wordt al met testen geleverd. Het bestand phpunit.xml in de root definieert de testomgeving, terwijl de map tests/ in twee mappen is gesplitst: tests/Unit en tests/Feature. Het onderscheid is conceptueel:

  • Unittests beproeven één enkele klasse of methode geïsoleerd, zonder het hele framework op te starten. Ze zijn snel en richten zich op pure logica (berekeningen, opmaak, kleine services).
  • Feature-tests verifiëren een HTTP-verzoek, een route, de database en meerdere klassen die samenwerken, van begin tot eind. Deze leveren in de praktijk meestal de meeste waarde op.

De handigste manier om ze uit te voeren is de wrapper van Laravel zelf:

php artisan test
# of rechtstreeks:
./vendor/bin/phpunit
# om één test te filteren:
php artisan test --filter=ProjectCanBeCreated

In phpunit.xml wordt de testomgeving doorgaans ingesteld met APP_ENV=testing en een SQLite-database in het geheugen (DB_CONNECTION=sqlite, DB_DATABASE=:memory:). Zo draaien tests elke keer op een schoon schema, zonder je echte database te raken.

Je eerste feature-test schrijven

Artisan volstaat om een testklasse te genereren:

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

Een eenvoudige feature-test begint met bevestigen dat een pagina correct laadt. Met PHPUnit-syntaxis:

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

Hier simuleert $this->get('/') een echt HTTP-verzoek; assertStatus en assertSee verifiëren het antwoord. De naam van de testmethode moet met test_ beginnen (of gemarkeerd zijn met het attribuut #[Test]) zodat PHPUnit hem herkent.

Databasetests en RefreshDatabase

Voor tests die de database raken is de RefreshDatabase-trait essentieel: hij reset het schema binnen een transactie vóór elke test en draait die daarna terug, zodat tests elkaar nooit beïnvloeden. Om data te produceren gebruik je factories:

public function test_project_is_persisted(): void
{
    $project = Project::factory()->create([
        'title' => ['nl' => 'Testproject'],
    ]);

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

assertDatabaseHas bevraagt rechtstreeks een rij. De tegenhanger assertDatabaseMissing is handig bij het testen van verwijderingen. Factories staan onder database/factories en genereren realistische willekeurige data via de fake()-helper.

Authenticatie, JSON en formulierverzending

In echte applicaties vereisen de meeste routes een ingelogde gebruiker. Laravel regelt dit in één regel met actingAs:

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

    $response = $this->actingAs($user)->post('/admin/projects', [
        'title_nl' => 'Nieuw project',
    ]);

    $response->assertRedirect('/admin/projects');
    $this->assertDatabaseHas('projects', ['title->nl' => 'Nieuw project']);
}

Voor JSON-gebaseerde API's zijn er methoden als getJson en postJson, plus structuurbewuste asserties zoals assertJson / assertJsonStructure:

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

Dezelfde tests beknopter schrijven met Pest

Pest is een testframework dat boven op PHPUnit is gebouwd; de motor is identiek, de syntaxis vloeiender. In plaats van klassen en methoden schrijf je functiegebaseerde tests. Dezelfde feature-test ziet er in Pest zo uit:

<?php

use App\Models\User;

it('laat een gemachtigde gebruiker een project toevoegen', function () {
    $user = User::factory()->create();

    $this->actingAs($user)
        ->post('/admin/projects', ['title_nl' => 'Nieuw project'])
        ->assertRedirect('/admin/projects');

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

De expect()-expressie biedt een leesbare keten van asserties (toBe, toBeTrue, toContain…). Traits zoals RefreshDatabase pas je in één keer toe op een hele map via uses() in het bestand tests/Pest.php. Om Pest op te zetten voeg je het pakket pestphp/pest toe met Composer en draai je php artisan pest:install; je bestaande PHPUnit-tests blijven onveranderd naast elkaar draaien.

Afhankelijkheden nabootsen: mocks en fakes

Goede tests maken nooit echt verbinding met externe services (e-mail, betaling, notificaties). Laravel levert hiervoor kant-en-klare fakes. Je kunt bijvoorbeeld bevestigen dat een notificatie is verzonden zonder een echte e-mail te versturen:

use Illuminate\Support\Facades\Mail;

Mail::fake();

// ... actie ...

Mail::assertSent(WelcomeMail::class);

Dezelfde gedachte geldt voor Queue::fake(), Event::fake(), Storage::fake() en Http::fake(). Die houden tests snel en deterministisch — ze hangen niet langer af van een netwerkverbinding of de status van een externe service.

Veelgestelde vragen

Moet ik PHPUnit of Pest kiezen?

Beide gebruiken dezelfde motor, dus het is geen wedstrijd in technische superioriteit. Wil je een klassegebaseerde, vertrouwde en enterprise-vriendelijke structuur, kies dan PHPUnit; geef je de voorkeur aan minder boilerplate en leesbare syntaxis, dan is Pest logisch. Voor nieuwe projecten wordt Pest steeds vaker de standaardkeuze, maar de gewoonten van je team moeten doorslaggevend zijn.

Moet ik alles testen?

Nee. Streven naar 100% dekking is meestal verspilling. Test eerst de bedrijfskritische flows (betaling, registratie, autorisatie, bestellingen) en de plekken die eerder zijn gebroken. Tests schrijven voor simpele getters/setters of voor de code van het framework zelf is verloren moeite.

Waarom zijn mijn tests traag?

De meest voorkomende oorzaken zijn het aanspreken van een echte database in plaats van SQLite in het geheugen, en het niet faken van externe services. Met :memory:-SQLite, RefreshDatabase en de juiste fakes kan een testsuite in enkele seconden draaien.

Wil je testen in je project verankeren? Heb je hulp nodig bij het opzetten van een betrouwbare testsuite op je bestaande Laravel-app, tot en met CI/CD-integratie, neem dan contact op — laten we je codebase samen verstevigen.

Bu kategorideki tüm yazılar →

Devamı için