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

# Aan de slag met Laravel-testen in Pest PHP

> Een introductie van Pest PHP, sinds Laravel 11 de default, vanuit het perspectief van een senior engineer. We behandelen de verschillen met PHPUnit, de migratiekosten en het gebruik van `arch()`-tests, gericht op invoering in echte projecten.

## Waarom Pest de default van Laravel werd

Sinds Laravel 11 wordt **Pest** als standaard testframework geselecteerd wanneer je een project aanmaakt met `laravel new`. PHPUnit is jarenlang de standaard testtool voor PHP geweest, maar Pest bouwt voort op PHPUnit en biedt een beknoptere, beter leesbare testsyntaxis.

<Info>
  Pest draait bovenop PHPUnit, dus bestaande PHPUnit-tests blijven gewoon werken. Je kunt stap voor stap migreren.
</Info>

Achter de officiële keuze voor Pest zit het doel om de frictie bij het schrijven van tests te verminderen. Door de rituele stappen van klassen definiëren en methodes schrijven weg te nemen en een syntaxis te bieden waarmee je je kunt concentreren op "wat je wilt testen", wordt het schrijven van tests vanzelf een gewoonte.

***

## De belangrijkste verschillen met PHPUnit

### Testsyntaxis

Het meest zichtbare verschil is hoe je tests schrijft.

<Tabs>
  <Tab title="Pest">
    ```php theme={null}
    test('een gebruiker kan inloggen', 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>

De functie `test()` van Pest ontvangt een closure. Omdat je geen klasse of methode hoeft te definiëren, is de bedoeling van de test vanaf de eerste regel duidelijk. Je kunt op dezelfde manier `it()` gebruiken. In het Engels lees je dan een natuurlijke zin, zoals `it('can login', ...)`.

### De `expect()`-API

Het meest kenmerkende aan Pest zijn de gekoppelde assertions met `expect()`.

```php theme={null}
test('de posts-API geeft JSON terug', 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();
});
```

Met `expect($value)->toBe()`, `->toBeNull()`, `->toContain()`, `->toHaveCount()` en meer schrijf je assertions die als natuurlijk Engels lezen. Je kunt ook meerdere assertions bundelen in een methodchain.

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

### Setup en teardown

Het equivalent van `setUp()` in PHPUnit is `beforeEach()`, en `tearDown()` komt overeen met `afterEach()`.

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

test('een ingelogde gebruiker kan het profiel openen', function () {
    $response = $this->get('/profile');
    $response->assertOk();
});

test('een ingelogde gebruiker kan het profiel bijwerken', function () {
    $response = $this->patch('/profile', ['name' => 'Nieuwe naam']);
    $response->assertRedirect('/profile');
});
```

### Datasets — table-driven tests

Wil je dezelfde testlogica uitvoeren met meerdere datasets, dan gebruik je `dataset`.

```php theme={null}
test('een ongeldig e-mailadres geeft een validatiefout', function (string $email) {
    $response = $this->postJson('/api/users', [
        'name' => 'Taro Tanaka',
        'email' => $email,
    ]);

    $response->assertUnprocessable();
})->with([
    'geen e-mail' => [''],
    'ongeldig formaat' => ['notanemail'],
    'dubbele @' => ['a@@example.com'],
]);
```

Het label van elke dataset (zoals `'geen e-mail'`) wordt aan de testnaam toegevoegd, zodat je in één oogopslag ziet bij welk patroon de test faalt.

***

## `arch()`-tests — automatische architectuurcontroles

De `arch()`-functie van Pest test de structuur van je codebase. Je kunt architectuurregels automatisch verifiëren, zoals "hangen controllers niet direct van modellen af" of "extenden modellen Eloquent".

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

test('controllers zijn final', function () {
    arch()->expect('App\Http\Controllers')
        ->toBeFinal();
});

test('serviceklassen hangen niet af van controllers', function () {
    arch()->expect('App\Services')
        ->not->toUse('App\Http\Controllers');
});
```

<Tip>
  `arch()`-tests worden uitgevoerd via statische analyse van de broncode. Ze sturen geen echte HTTP-requests en raken de database niet aan, waardoor ze extreem snel zijn.
</Tip>

Pest biedt ook presets met veelgebruikte architectuurregels.

```php theme={null}
test('volgt de Laravel-architectuurregels', function () {
    arch()->preset()->laravel();
});
```

De preset `laravel()` verifieert in één keer regels die aansluiten bij de gangbare Laravel-conventies, zoals modelnaamgeving, controller-overerving en de structuur van middleware.

***

## Praktijkvoorbeelden in een Laravel-project

### Een test aanmaken

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

Voer je dit uit met de standaardconfiguratie van Laravel 11 of hoger, dan wordt een testbestand in Pest-stijl gegenereerd.

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

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

### De testhelpers van Laravel gewoon blijven gebruiken

Omdat Pest de `TestCase` van Laravel extendt, kun je alle Laravel-testhelpers gewoon blijven gebruiken: `actingAs()`, `assertDatabaseHas()`, de HTTP-testhelpers en meer.

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

test('een gebruiker kan zijn eigen post verwijderen', 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('de post van een andere gebruiker kan niet worden verwijderd', 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);
});
```

### Factory's en databasetransacties

Ook de traits `RefreshDatabase` en `DatabaseTransactions` pas je eenvoudig toe met `uses()`. Zet je het bovenaan een bestand, dan geldt het voor dat hele bestand.

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

Configureer je dit eenmaal in `tests/Pest.php`, dan is `RefreshDatabase` automatisch actief voor al je Feature-tests. Je kunt het in individuele testbestanden nog steeds overschrijven.

***

## Naast bestaande PHPUnit-tests werken

Pest en PHPUnit kunnen naast elkaar bestaan in hetzelfde project. Je hoeft bestaande PHPUnit-tests niet te herschrijven; het is genoeg om nieuwe tests in Pest-stijl te schrijven.

```shell theme={null}
./vendor/bin/pest       # Voer alle tests uit met Pest (inclusief PHPUnit-tests)
./vendor/bin/pest --filter="gebruiker"  # Filteren op testnaam
php artisan test        # Ook via het Artisan-commando draait Pest
```

<Info>
  Vanaf Laravel 11 gebruikt `php artisan test` automatisch Pest wanneer Pest is geïnstalleerd.
</Info>

### Zo pak je de migratie aan

1. Voeg eerst de `uses()`-configuratie toe aan `tests/Pest.php`
2. Schrijf nieuw toegevoegde tests in Pest-stijl
3. Migreer bestaande PHPUnit-tests stukje bij beetje, terwijl je controleert of alles blijft werken

Je hoeft niet gehaast alle tests om te schrijven. De syntaxis van Pest heeft een lagere leercurve dan PHPUnit, waardoor de adoptie binnen je team doorgaans soepel verloopt.

***

## Samenvatting

| Vergelijkingspunt       | PHPUnit            | Pest                              |
| ----------------------- | ------------------ | --------------------------------- |
| Testdefinitie           | Klasse + methode   | Functies `test()` / `it()`        |
| Assertions              | `$this->assert*()` | `expect()->to*()`                 |
| Setup                   | `setUp()`          | `beforeEach()`                    |
| Data-driven             | `@dataProvider`    | `->with()`                        |
| Architectuurverificatie | Geen               | `arch()`                          |
| Uitvoeringssnelheid     | Standaard          | Gelijkwaardig (draait op PHPUnit) |

Pest is geen vervanging van PHPUnit, maar een laag bovenop PHPUnit. De integratie met Laravel gaat diep — zo diep dat Pest tegenwoordig standaard wordt geselecteerd bij het genereren van een starter kit. De kosten om het in een bestaand project te introduceren zijn laag: begin gewoon met je nieuwe tests en je profiteert er meteen van.

Hoe meer tests je schrijft, hoe sneller je bugs vindt en hoe lager de psychologische drempel voor refactoren wordt. Pest is een gereedschap dat precies die "frictie van het schrijven van tests" wegneemt.

<Card title="Officiële Pest-documentatie" icon="book-open" href="https://pestphp.com/docs">
  Raadpleeg de officiële documentatie voor alle functies van Pest, zoals datasets, coverage en parallelle uitvoering.
</Card>


## Related topics

- [Geavanceerd testen met Pest](/nl/advanced/testing-pest.md)
- [Aan de slag - VOICEVOX for Laravel](/nl/packages/laravel-voicevox/getting-started.md)
- [Wat is Laravel?](/nl/introduction.md)
- [Databasetests](/nl/database-testing.md)
- [Consoletests](/nl/console-tests.md)
