Aller au contenu

Tests Backend — Pest PHP

Documentation des tests backend avec Pest PHP pour Primatch.


Structure des tests

tests/
├── Unit/
│   └── Domain/
│       ├── Game/
│       │   ├── GameServiceTest.php
│       │   └── ScoreTest.php          # Value Object
│       └── Auth/
│           └── AuthServiceTest.php
├── Feature/
│   └── Api/V1/
│       ├── Auth/
│       │   ├── LoginTest.php
│       │   └── RegisterTest.php
│       └── Game/
│           ├── CreateGameTest.php
│           └── SubmitScoreTest.php
└── Architecture/
    ├── DomainTest.php      # Vérifie que Domain n'importe pas Infrastructure
    └── NamingTest.php      # Conventions de nommage

Test d'intégration — Endpoint

<?php
// tests/Feature/Api/V1/Game/CreateGameTest.php

use App\Models\User;

describe('POST /api/v1/games', function () {
    it('creates a game when authenticated with valid data', function () {
        $user = User::factory()->create();

        $response = $this
            ->actingAs($user, 'api')
            ->postJson('/api/v1/games', [
                'type' => 'friendly',
                'scheduled_at' => now()->addDays(1)->toIso8601String(),
            ]);

        $response->assertCreated()
                 ->assertJsonStructure(['data' => ['id', 'type', 'status']]);

        $this->assertDatabaseHas('games', ['type' => 'friendly', 'creator_id' => $user->id]);
    });

    it('returns 401 when not authenticated', function () {
        $this->postJson('/api/v1/games', [])->assertUnauthorized();
    });

    it('returns 422 with invalid type', function () {
        $user = User::factory()->create();

        $this->actingAs($user, 'api')
             ->postJson('/api/v1/games', ['type' => 'invalid'])
             ->assertUnprocessable()
             ->assertJsonValidationErrors(['type']);
    });
});

Test unitaire — Service

<?php
// tests/Unit/Domain/Game/GameServiceTest.php

use App\Domain\Game\Services\GameService;
use App\Domain\Game\Repositories\GameRepositoryInterface;
use App\Domain\Game\DTOs\CreateGameDTO;

it('dispatches GameCreated event when creating a game', function () {
    Event::fake();

    $mockRepo = Mockery::mock(GameRepositoryInterface::class);
    $mockRepo->shouldReceive('create')->once()->andReturn(/* game */);

    $service = new GameService($mockRepo);
    $service->createGame(new CreateGameDTO(/* ... */));

    Event::assertDispatched(GameCreated::class);
});

Tests d'architecture (Pest Arch)

<?php
// tests/Architecture/DomainTest.php

arch('Domain layer has no dependency on Infrastructure')
    ->expect('App\Domain')
    ->not->toUse('App\Infrastructure');

arch('Controllers only use Domain services')
    ->expect('App\Http\Controllers')
    ->not->toUse('App\Infrastructure');

arch('All Services are final')
    ->expect('App\Domain\*\Services')
    ->toBeFinal();