Pest Datasets - Wiederverwendbare Testdaten
Diese Dokumentation beschreibt die verfügbaren Pest Datasets für parametrisierte Tests in Hermeneus.
Übersicht
Datasets befinden sich in tests/Datasets/ und bieten wiederverwendbare Testdaten für verschiedene Domänen:
- users.php - User-Rollen und Authentifizierung
- vocab.php - Vokabel- und Morphologie-Daten
- uebungen.php - Übungs-Module und Konfigurationen
Was sind Datasets?
Datasets ermöglichen parametrisierte Tests, die mit verschiedenen Eingabewerten ausgeführt werden:
test('addition funktioniert', function (int $a, int $b, int $expected) {
expect($a + $b)->toBe($expected);
})->with([
[1, 2, 3],
[5, 5, 10],
[0, 0, 0],
]);Benannte Datasets können wiederverwendet werden:
dataset('numbers', [
[1, 2, 3],
[5, 5, 10],
]);
test('addition', fn($a, $b, $expected) => expect($a + $b)->toBe($expected))
->with('numbers');User Datasets (tests/Datasets/users.php)
roles - Alle Rollen
Alle verfügbaren User-Rollen.
Werte:
admineditortesterteacheruser
Verwendung:
test('user kann einloggen', function (string $role) {
actingAsRole($role);
$response = getJson('/api/user');
expect($response->status())->toBe(200);
})->with('roles');Ausgabe beim Testen:
✓ user kann einloggen (admin)
✓ user kann einloggen (editor)
✓ user kann einloggen (tester)
✓ user kann einloggen (teacher)
✓ user kann einloggen (user)elevated_roles - Erhöhte Rechte
Rollen mit erhöhten Berechtigungen (Admin, Editor, Tester).
Werte:
admineditortester
Verwendung:
test('nur privilegierte user können übung bearbeiten', function (string $role) {
actingAsRole($role);
$response = putJson('/api/uebungen/1', ['title' => 'Geändert']);
expect($response->status())->toBe(200);
})->with('elevated_roles');
test('normale user werden blockiert', function (string $role) {
actingAsRole($role);
$response = putJson('/api/uebungen/1', ['title' => 'Geändert']);
expect($response->status())->toBe(403);
})->with('regular_roles');regular_roles - Normale Rollen
Rollen ohne erhöhte Berechtigungen (Teacher, User).
Werte:
teacheruser
Verwendung:
test('normale user können eigene texte sehen', function (string $role) {
actingAsRole($role);
$response = getJson('/api/my-texts');
expect($response->status())->toBe(200);
})->with('regular_roles');base_data_users - Komplette User-Details
Vollständige Informationen zu allen Base-Data Usern.
Struktur:
[
'admin' => [
'username' => 'bruce.wayne',
'email' => 'bruce.wayne@gotham-academy.test',
'role' => 'admin',
],
// ...
]Verwendung:
test('user hat korrekte email', function (array $userData) {
$user = getBaseDataUser($userData['role']);
expect($user->username)->toBe($userData['username']);
expect($user->email)->toBe($userData['email']);
expect($user->role)->toBe($userData['role']);
})->with('base_data_users');Vokabel Datasets (tests/Datasets/vocab.php)
wortarten - Alle Wortarten
Alle Wortarten im Hermeneus-Glossarium.
Werte:
nomenverbadjektivpronomenpartikelnumeraleeigennamewendung
Verwendung:
test('lemma kann für wortart erstellt werden', function (string $wortart) {
$lemma = createLemmaForWortart($wortart);
expect($lemma->wortart)->toBe($wortart);
})->with('wortarten');morphable_wortarten - Morphologisierbare Wortarten
Nur Wortarten mit Flexionsformen.
Werte:
nomenverbadjektivpronomennumerale
Ausgeschlossen:
partikel(keine Flexion)eigenname(keine Flexion)wendung(keine Flexion)
Verwendung:
test('lemma kann morphologisiert werden', function (string $wortart) {
$lemma = createLemmaForWortart($wortart);
expect($lemma)->toBeMorphable();
})->with('morphable_wortarten');deklinationsklassen - Deklinationsklassen
Deklinationsklassen für Nomina mit Beispielen.
Struktur:
[
'a' => ['klasse' => 'a', 'beispiel' => 'puella, -ae f.'],
'o' => ['klasse' => 'o', 'beispiel' => 'dominus, -i m.'],
'kons' => ['klasse' => 'kons', 'beispiel' => 'rex, regis m.'],
'e' => ['klasse' => 'e', 'beispiel' => 'res, rei f.'],
'u' => ['klasse' => 'u', 'beispiel' => 'manus, -us f.'],
'gem' => ['klasse' => 'gem', 'beispiel' => 'civis, -is m./f.'],
]Verwendung:
test('deklinationsklasse wird korrekt zugeordnet', function (array $dekl) {
$nomen = createNomen($dekl['klasse']);
expect($nomen->deklinationsklasse)->toBe($dekl['klasse']);
})->with('deklinationsklassen');konjugationsklassen - Konjugationsklassen
Konjugationsklassen für Verben mit Beispielen.
Struktur:
[
'a' => ['klasse' => 'a', 'beispiel' => 'amare'],
'e' => ['klasse' => 'e', 'beispiel' => 'monere'],
'kons' => ['klasse' => 'kons', 'beispiel' => 'legere'],
'i' => ['klasse' => 'i', 'beispiel' => 'audire'],
'gem' => ['klasse' => 'gem', 'beispiel' => 'capere'],
]Verwendung:
test('konjugationsklasse wird erkannt', function (array $konj) {
$verb = Verb::where('lemma', $konj['beispiel'])->first();
expect($verb->konjugationsklasse)->toBe($konj['klasse']);
})->with('konjugationsklassen');genera - Geschlechter
Grammatikalische Genera.
Struktur:
[
'm' => ['genus' => 'm', 'bezeichnung' => 'maskulin'],
'f' => ['genus' => 'f', 'bezeichnung' => 'feminin'],
'n' => ['genus' => 'n', 'bezeichnung' => 'neutrum'],
]Verwendung:
test('genus wird korrekt gespeichert', function (array $genusData) {
$nomen = Nomen::factory()->create([
'genus' => $genusData['genus']
]);
expect($nomen->genus)->toBe($genusData['genus']);
})->with('genera');kasus - Fälle
Lateinische Kasus.
Struktur:
[
'nom' => ['kasus' => 'nom', 'bezeichnung' => 'Nominativ'],
'gen' => ['kasus' => 'gen', 'bezeichnung' => 'Genitiv'],
'dat' => ['kasus' => 'dat', 'bezeichnung' => 'Dativ'],
'akk' => ['kasus' => 'akk', 'bezeichnung' => 'Akkusativ'],
'abl' => ['kasus' => 'abl', 'bezeichnung' => 'Ablativ'],
'vok' => ['kasus' => 'vok', 'bezeichnung' => 'Vokativ'],
]Verwendung:
test('kasus werden in morphostring kodiert', function (array $kasusData) {
$morphoString = createMorphoStringWithKasus($kasusData['kasus']);
expect($morphoString)->toContain($kasusData['kasus']);
})->with('kasus');numeri - Singular/Plural
Numerus-Kategorien.
Struktur:
[
'sg' => ['numerus' => 'sg', 'bezeichnung' => 'Singular'],
'pl' => ['numerus' => 'pl', 'bezeichnung' => 'Plural'],
]Verwendung:
test('numerus wird erkannt', function (array $numerusData) {
$form = createFormWithNumerus($numerusData['numerus']);
expect($form->numerus)->toBe($numerusData['numerus']);
})->with('numeri');Übungs Datasets (tests/Datasets/uebungen.php)
uebung_aliases - Alle Übungsmodule
Alle registrierten Übungsmodule aus der UebungenRegistry.
Dynamisch geladen: Wird zur Laufzeit aus der Registry generiert.
Beispielwerte:
uebung-bedeutungen-zuordnenuebung-formen-bestimmenuebung-vokabelnlernen- ...
Verwendung:
test('übung kann erstellt werden', function (string $alias) {
actingAsAdmin();
$response = postJson("/api/uebungen/{$alias}/store", [
'title' => 'Test Übung',
'content_data' => getDefaultContentData($alias),
]);
expect($response)->toBeSuccessfulApiResponse();
})->with('uebung_aliases');Wichtig: Alle verfügbaren Module werden getestet!
absolvable_uebungen - Absolvierbare Übungen
Nur Übungen mit absolvable: true in config.json.
Dynamisch gefiltert: Basiert auf Registry-Konfiguration.
Verwendung:
test('übung kann absolviert werden', function (string $alias) {
actingAsUser();
$uebung = createUebung($alias);
$response = postJson("/api/uebungen/{$uebung->id}/absolve");
expect($response)->toBeSuccessfulApiResponse();
})->with('absolvable_uebungen');evaluable_uebungen - Evaluierbare Übungen
Nur Übungen mit evaluable: true in config.json.
Dynamisch gefiltert: Basiert auf Registry-Konfiguration.
Verwendung:
test('übung kann ausgewertet werden', function (string $alias) {
actingAsUser();
$uebung = createUebung($alias);
$submission = createSubmission($uebung);
$response = postJson("/api/uebungen/{$uebung->id}/evaluate", [
'submission' => $submission,
]);
expect($response)->toBeSuccessfulApiResponse();
expect($response->json())->toHaveKey('evaluation');
})->with('evaluable_uebungen');timetrackable_uebungen - Zeiterfassbare Übungen
Nur Übungen mit timetrackable: true in config.json.
Dynamisch gefiltert: Basiert auf Registry-Konfiguration.
Verwendung:
test('zeiterfassung funktioniert', function (string $alias) {
actingAsUser();
$uebung = createUebung($alias);
$response = postJson("/api/uebungen/{$uebung->id}/track-time", [
'duration' => 120, // Sekunden
]);
expect($response)->toBeSuccessfulApiResponse();
})->with('timetrackable_uebungen');uebung_crud_examples - CRUD-Beispieldaten
Konkrete Beispieldaten für verschiedene Übungstypen (nicht dynamisch).
Struktur:
[
'uebung-bedeutungen-zuordnen' => [
'alias' => 'uebung-bedeutungen-zuordnen',
'type' => 'vocab-based',
],
'uebung-formen-bestimmen' => [
'alias' => 'uebung-formen-bestimmen',
'type' => 'morphology-based',
],
'uebung-vokabelnlernen' => [
'alias' => 'uebung-vokabelnlernen',
'type' => 'vocab-based',
],
]Verwendung:
test('crud operations für übungstyp', function (array $example) {
actingAsEditor();
$alias = $example['alias'];
$type = $example['type'];
// Create
$response = postJson("/api/uebungen/{$alias}/store", [
'title' => "Test {$alias}",
]);
expect($response)->toBeSuccessfulApiResponse();
$id = $response->json('data.id');
// Read
$response = getJson("/api/uebungen/{$id}");
expect($response)->toBeSuccessfulApiResponse();
// Update
$response = putJson("/api/uebungen/{$id}", [
'title' => "Updated {$alias}",
]);
expect($response)->toBeSuccessfulApiResponse();
// Delete
$response = deleteJson("/api/uebungen/{$id}");
expect($response)->toBeSuccessfulApiResponse();
})->with('uebung_crud_examples');Best Practices
1. Spezifische Datasets bevorzugen
// SCHLECHT: Zu breit
test('test', function (string $role) {
// ...
})->with('roles'); // Testet auch irrelevante Rollen
// GUT: Präzise
test('test', function (string $role) {
// ...
})->with('elevated_roles'); // Nur relevante Rollen2. Datasets kombinieren
test('user kann übung für wortart erstellen', function (string $role, string $wortart) {
actingAsRole($role);
$lemma = createLemmaForWortart($wortart);
// Test-Code
})
->with('elevated_roles')
->with('morphable_wortarten');Erzeugt: Kombinatorische Tests (elevated_roles × morphable_wortarten)
3. Eigene Datasets definieren
// In Test-Datei
dataset('test_uebungen', [
'uebung-bedeutungen-zuordnen',
'uebung-formen-bestimmen',
]);
test('test', fn($alias) => /* ... */)->with('test_uebungen');4. Named Datasets für Lesbarkeit
// Ohne Namen (unklar)
->with([
['admin', true],
['user', false],
]);
// Mit Namen (klar)
->with([
'admin can access' => ['admin', true],
'user is blocked' => ['user', false],
]);Ausgabe:
✓ test (admin can access)
✗ test (user is blocked)Erweiterte Nutzung
Lazy Datasets
Für aufwendige Berechnungen:
dataset('expensive_data', function () {
return expensive_computation();
});Shared Datasets
Datasets können über mehrere Test-Dateien geteilt werden (bereits implementiert in tests/Datasets/).
Closure-basierte Datasets
dataset('dynamic_users', function () {
yield fn() => getBaseDataUser('admin');
yield fn() => getBaseDataUser('editor');
});Troubleshooting
"Dataset not found"
Stelle sicher, dass die Dataset-Datei in tests/Datasets/ existiert und korrekt benannt ist.
"Empty dataset"
Dynamische Datasets (uebung_aliases, etc.) benötigen eine funktionierende Applikation mit geladener Registry.
"Too many test cases"
Bei kombinatorischen Tests mit with()->with():
// Erzeugt: 5 roles × 5 wortarten = 25 Tests
->with('roles')
->with('wortarten')
// Reduziere auf relevante Kombinationen:
->with('elevated_roles') // 3 roles
->with('morphable_wortarten') // 5 wortarten = 15 Tests