Pest-Konfiguration und globale Test-Infrastruktur
Diese Dokumentation beschreibt die zentrale Pest-Konfiguration in tests/Pest.php und die globalen Test-Infrastruktur-Komponenten.
Übersicht
Die Pest-Konfiguration definiert:
- Test-Scopes mit automatischen Traits (DatabaseTransactions)
- Helper-Funktionen für Authentifizierung und Übungen
- Custom Expectations für domänenspezifische Assertions
- Base-Data User Mapping für konsistente Testdaten
Datei: tests/Pest.php
Test-Scopes und Traits
// Feature-Tests: TestCase + DatabaseTransactions
uses(Tests\TestCase::class, WithDatabaseTransactions::class)->in('Feature');
// Unit-Tests: Nur TestCase (keine DB-Transactions)
uses(Tests\TestCase::class)->in('Unit');Bedeutung:
- Alle Tests in
tests/Feature/erhalten automatischDatabaseTransactions - Alle Tests in
tests/Unit/haben keine automatischen Rollbacks - Modul-Tests (
modules/*/*/tests/) müssenuses()lokal definieren
Beispiel Modul-Test:
// modules/Uebungen/UebungVorlage/tests/Feature/UebungVorlageAPITest.php
<?php
use Tests\Support\WithDatabaseTransactions;
uses(WithDatabaseTransactions::class);
test('kann übung erstellen', function () {
// Test-Code
});Base-Data User Mapping
const BASE_DATA_USERS = [
'admin' => 'bruce.wayne',
'editor' => 'harvey.dent',
'tester' => 'james.gordon',
'teacher' => 'selina.kyle',
'user' => 'joker',
];Diese Konstante mappt Rollen auf konkrete Usernamen in der Test-Datenbank.
Wichtig: Die User müssen via php artisan test:setup in der Datenbank existieren!
Globale Helper-Funktionen
Authentifizierung
getBaseDataUser(string $role): User
Holt einen Base-Data User anhand der Rolle.
$admin = getBaseDataUser('admin');
expect($admin->username)->toBe('bruce.wayne');
$teacher = getBaseDataUser('teacher');
expect($teacher->role)->toBe('teacher');Wirft Exception bei:
- Unbekannter Rolle
- User nicht in Datenbank gefunden (Setup fehlt)
actingAsRole(string $role): User
Meldet einen Base-Data User an und gibt ihn zurück.
$admin = actingAsRole('admin');
// $admin ist jetzt eingeloggt
$response = getJson('/api/admin/dashboard');
expect($response->status())->toBe(200);Convenience-Funktionen
Für häufig verwendete Rollen gibt es spezifische Funktionen:
actingAsAdmin(); // bruce.wayne
actingAsEditor(); // harvey.dent
actingAsTester(); // james.gordon
actingAsTeacher(); // selina.kyle
actingAsUser(); // jokerVerwendung in Tests:
test('admin kann dashboard zugreifen', function () {
actingAsAdmin();
$response = getJson('/api/admin/dashboard');
expect($response->status())->toBe(200);
});
test('normale user werden blockiert', function () {
actingAsUser();
$response = getJson('/api/admin/dashboard');
expect($response->status())->toBe(403);
});Übungs-Helper
getUebungAliases(): array
Gibt alle registrierten Übungs-Aliase aus der UebungenRegistry zurück.
$aliases = getUebungAliases();
// ['uebung-bedeutungen-zuordnen', 'uebung-formen-bestimmen', ...]
expect($aliases)->toContain('uebung-bedeutungen-zuordnen');getRegistryEntry(string $alias): mixed
Gibt den vollständigen Registry-Eintrag einer Übung zurück.
$entry = getRegistryEntry('uebung-bedeutungen-zuordnen');
expect($entry)->not->toBeNull();
expect($entry->config)->toHaveKey('options');Custom Expectations
Pest wurde mit Hermeneus-spezifischen Expectations erweitert.
Lemma/Vokabel-Expectations
toBeValidLemma()
Prüft ob ein Lemma-Objekt valide ist.
Validiert:
- Lemma ist nicht null
- Feld
lemmaist nicht leer - Feld
bedeutungist nicht leer
expect($lemma)->toBeValidLemma();Implementierung:
expect()->extend('toBeValidLemma', function () {
$lemma = $this->value;
expect($lemma)->not->toBeNull('Lemma sollte nicht null sein');
expect($lemma->lemma)->not->toBeEmpty('Lemma-Feld sollte nicht leer sein');
expect($lemma->bedeutung)->not->toBeEmpty('Bedeutung sollte nicht leer sein');
return $this;
});toBeMorphable()
Prüft ob ein Lemma morphologisierbar ist.
Validiert:
- Property
IsMorphologisierbarexistiert IsMorphologisierbaristtrue
$verb = Verb::find(1);
expect($verb)->toBeMorphable();Status-Expectations
toHaveValidStatus()
Prüft ob ein Model einen gültigen Status hat.
Gültige Status:
draftpendingpublishedarchived
$uebung = Uebung::find(1);
expect($uebung)->toHaveValidStatus();Übungs-Expectations
toBeValidUebung()
Prüft ob eine Übung valide ist.
Validiert:
- Übung ist nicht null
- Relation
base_uebungexistiert base_uebungist Instanz vonUebung
$uebung = UebungBedeutungenZuordnen::find(1);
expect($uebung)->toBeValidUebung();toHaveContentData()
Prüft ob content_data vorhanden ist.
Validiert:
- Property
content_dataexistiert content_dataist nicht leer
$uebung = UebungBedeutungenZuordnen::find(1);
expect($uebung)->toHaveContentData();toHaveValidGravitas()
Prüft ob das Gravitas-Level valide ist.
Validiert:
- Property
cfg_max_gravitas_levelexistiert - Wert ist zwischen 0 und 100
$uebung = Uebung::find(1);
expect($uebung)->toHaveValidGravitas();Hinweis: Funktioniert sowohl mit Uebung als auch mit spezifischen Übungs-Models.
API-Response-Expectations
toBeSuccessfulApiResponse()
Prüft auf erfolgreiche API-Response.
Validiert:
- HTTP Status 200
- Falls
success-Feld existiert:success === true
$response = postJson('/api/uebungen/store', [...]);
expect($response)->toBeSuccessfulApiResponse();toHaveApiError(int $expectedStatus = 422)
Prüft auf API-Fehler mit bestimmtem Status-Code.
Default: 422 (Validation Error)
$response = postJson('/api/uebungen/store', []);
expect($response)->toHaveApiError(422);
$response = getJson('/api/uebungen/999999');
expect($response)->toHaveApiError(404);Datasets
Siehe separates Dokument zu Datasets oder Hauptdokumentation.
Kurz:
tests/Datasets/users.php- User-Rollen und Base-Datatests/Datasets/vocab.php- Vokabel-bezogene Datentests/Datasets/uebungen.php- Übungs-bezogene Daten
TestCase.php
Die zentrale Tests\TestCase Klasse definiert:
Setup-Methode
protected function setUp(): void
{
parent::setUp();
config(['app.url' => 'http://hermeneus.test']);
URL::forceRootUrl('http://hermeneus.test');
Schema::enableForeignKeyConstraints();
$this->disableExceptionHandling();
}Wichtig:
- Foreign Keys sind aktiviert (Datenbankintegrität)
- Exception Handling ist deaktiviert (bessere Fehlerausgabe)
Helper-Methoden
clearTestCache()
Löscht Test-relevante Cache-Keys.
test('cache wird geleert', function () {
$this->clearTestCache();
// Test-Code
});Löscht:
scope_lookupvocab_all
disableExceptionHandling() / withExceptionHandling()
Deaktiviert/Aktiviert Laravel Exception Handling.
test('zeigt rohe exception', function () {
$this->disableExceptionHandling(); // Default
// Wirft Exception direkt, kein JSON-Error-Response
getJson('/api/broken-route');
});
test('nutzt laravel exception handler', function () {
$this->withExceptionHandling();
// Gibt JSON-Error-Response zurück
$response = getJson('/api/broken-route');
expect($response->status())->toBe(500);
});Wichtige Hinweise
Base-Data User sind Pflicht
Alle Helper-Funktionen setzen voraus, dass die Test-Datenbank mit Base-Data initialisiert wurde.
Empfohlener Weg (automatisch):
# Intelligenter Test-Runner mit automatischem Setup
npm run testDer neue test:run Command prüft automatisch, ob die Datenbank bereit ist und führt bei Bedarf ein Setup durch.
Manuelles Setup:
# Nur Setup ohne Tests
php artisan test:setup
# Oder über NPM
npm run test:setupBei fehlendem Setup:
RuntimeException: Base-Data User 'bruce.wayne' nicht gefunden.
Bitte `php artisan test:setup` ausfuehren.Siehe auch: TestRunCommand für Details zur Smart-Check-Logik
Module-Tests benötigen explizites uses()
Module-Tests definieren ihre Uses-Statements selbst:
// modules/Uebungen/UebungVorlage/tests/Pest.php (optional)
uses(Tests\TestCase::class, WithDatabaseTransactions::class)
->in(__DIR__);
// ODER direkt in Test-Datei
uses(WithDatabaseTransactions::class);Factory vs. Base-Data
VERALTET:
$user = User::factory()->create(); // Erzeugt temporären User
$this->actingAs($user);AKTUELL:
actingAsAdmin(); // Nutzt bruce.wayne aus Base-DataVorteile Base-Data:
- Konsistente User-IDs über Tests hinweg
- Keine temporären Datenbank-Einträge
- Schnellere Testausführung (kein Factory-Overhead)
- Realitätsnähere Testdaten
Erweiterte Nutzung
Custom Expectations hinzufügen
Neue Expectations können in tests/Pest.php definiert werden:
expect()->extend('toHaveVocabData', function () {
$uebung = $this->value;
expect($uebung->content_data)->toHaveKey('vocab_ids');
expect($uebung->content_data['vocab_ids'])->toBeArray();
expect($uebung->content_data['vocab_ids'])->not->toBeEmpty();
return $this;
});
// Verwendung:
expect($uebung)->toHaveVocabData();Neue Helper-Funktionen
function createTestUebung(string $alias): mixed
{
$entry = getRegistryEntry($alias);
$modelClass = $entry->modelClass;
return $modelClass::factory()->create();
}
// Verwendung:
test('uebung wird erstellt', function () {
$uebung = createTestUebung('uebung-bedeutungen-zuordnen');
expect($uebung)->toBeValidUebung();
});Troubleshooting
"Base-Data User nicht gefunden"
php artisan test:setup"Class 'WithDatabaseTransactions' not found"
use Tests\Support\WithDatabaseTransactions;
uses(WithDatabaseTransactions::class);Tests hinterlassen Datenbank-Artefakte
Prüfe ob uses(WithDatabaseTransactions::class) definiert ist.
"Unknown role: xyz"
Nur folgende Rollen sind definiert:
admineditortesterteacheruser