Integration-Tests
Übersicht
Integration-Tests sind eine spezielle Kategorie von Tests, die echte Aufrufe an externe Dienste durchführen und deren tatsächliche Antworten validieren. Im Gegensatz zu Feature- und Unit-Tests, die externe Abhängigkeiten mocken, verwenden Integration-Tests die realen APIs.
Wann werden Integration-Tests verwendet?
Integration-Tests sind speziell für folgende Szenarien vorgesehen:
- AI-Service-Integrationen: Tests für Tiro, Varro, Grammaticus, AeliusDonatus
- Drittanbieter-APIs: Externe Services wie Anthropic Claude, OpenAI, etc.
- Antwortformat-Validierung: Prüfung echter API-Antwortstrukturen
- Qualitätsprüfung: Validierung der Qualität generierter Inhalte
- Regression-Tests: Erkennung von Änderungen nach API-Updates
Unterschied zu anderen Test-Kategorien
| Kategorie | Externe Calls | API-Kosten | Ausführung | Zweck |
|---|---|---|---|---|
| Unit-Tests | Keine | Nein | Automatisch | Isolierte Komponenten-Tests |
| Feature-Tests | Gemockt | Nein | Automatisch | Features aus Nutzersicht |
| Integration-Tests | Echt | Ja | Manuell/On-Demand | Externe API-Validierung |
Speicherorte
Hauptanwendung
tests/Integration/
├── AI/
│ ├── VarroIntegrationTest.php
│ ├── TiroIntegrationTest.php
│ └── GrammaticusIntegrationTest.php
└── ExternalServices/
└── ThirdPartyAPITest.phpModule
modules/Services/HermeneusAI/tests/Integration/
└── AIServiceIntegrationTest.phpPHPUnit-Konfiguration
In der phpunit.xml ist die Integration-Testsuite separat definiert:
xml
<testsuite name="Integration">
<directory suffix="Test.php">./tests/Integration</directory>
<directory suffix="Test.php">./modules/*/*/tests/Integration</directory>
</testsuite>Wichtig: Diese Testsuite wird NICHT automatisch bei php artisan test ausgeführt!
Test-Ausführung
Alle Integration-Tests
bash
# Via Testsuite
php artisan test --testsuite=Integration
# Via Group-Tag
php artisan test --group=integrationEinzelne Integration-Tests
bash
# Einzelne Datei
php artisan test tests/Integration/AI/VarroIntegrationTest.php
# Einzelnes Modul
php artisan test modules/Services/HermeneusAI/tests/Integration/Mit Test-Runner
bash
# Mit Smart-Check und Setup
php artisan test:run --testsuite=Integration
# Mit frischer Datenbank
php artisan test:run --fresh --testsuite=IntegrationBest Practices
1. Group-Tagging
Alle Integration-Tests sollten mit @group integration getaggt werden:
php
<?php
use function Pest\Laravel\{postJson};
test('varro validiert echte glossarium-einträge', function () {
actingAsAdmin();
$response = postJson('/api/ai/varro/validate', [
'lemma' => 'discere',
'bedeutung' => 'lernen',
'wortart' => 'verb',
]);
expect($response)->toBeSuccessfulApiResponse();
expect($response->json('data.is_valid'))->toBeTrue();
})->group('integration');2. Sparsame Verwendung
Da Integration-Tests echte API-Credits verbrauchen:
- Nicht für jeden Test: Nur kritische Pfade testen
- Nicht in CI/CD per Default: Gezielt triggern, nicht bei jedem Push
- Sinnvolle Frequenz: Wöchentlich oder vor Releases ausführen
- Dokumentation: Erwartete Kosten pro Testlauf dokumentieren
3. Realistische Testdaten
php
test('tiro generiert lateinischen prüfungstext', function () {
actingAsAdmin();
$response = postJson('/api/ai/tiro/generate-exam-text', [
'topic' => 'Caesars Gallienkrieg',
'difficulty' => 'advanced',
'word_count' => 150,
'grammatical_phenomena' => ['ablativus absolutus', 'cum-Sätze'],
]);
expect($response)->toBeSuccessfulApiResponse();
$text = $response->json('data.text');
expect($text)->toBeString();
expect($text)->toContain('Caesar'); // Thematische Validierung
expect(str_word_count($text))->toBeGreaterThan(140); // Längenprüfung
})->group('integration');4. Error-Handling testen
php
test('varro gibt sinnvolle fehlermeldung bei ungültiger eingabe', function () {
actingAsAdmin();
$response = postJson('/api/ai/varro/validate', [
'lemma' => '', // Ungültige Eingabe
'bedeutung' => 'lernen',
'wortart' => 'verb',
]);
expect($response)->toHaveApiError(422);
expect($response->json('errors'))->toHaveKey('lemma');
})->group('integration');5. Timeout-Konfiguration
AI-Services können länger brauchen - angemessene Timeouts setzen:
php
test('tiro generiert langen text ohne timeout', function () {
// Timeout auf 60 Sekunden setzen
$this->timeout(60);
actingAsAdmin();
$response = postJson('/api/ai/tiro/generate-text', [
'topic' => 'Römische Geschichte',
'word_count' => 500, // Längerer Text
]);
expect($response)->toBeSuccessfulApiResponse();
})->group('integration')->timeout(60000); // MillisekundenBeispiel: Vollständiger Integration-Test
php
<?php
use function Pest\Laravel\{postJson};
/**
* Integration-Tests für Varro (AI-Glossarium-Validator)
*
* Hinweis: Diese Tests verbrauchen echte API-Credits!
* Nur bei Bedarf ausführen: php artisan test --group=integration
*/
beforeEach(function () {
actingAsAdmin();
});
test('varro validiert korrekte nomen-einträge', function () {
$response = postJson('/api/ai/varro/validate', [
'lemma' => 'puella',
'bedeutung' => 'Mädchen',
'wortart' => 'nomen',
'genus' => 'f',
'deklinationsklasse' => 'a',
]);
expect($response)->toBeSuccessfulApiResponse();
expect($response->json('data.is_valid'))->toBeTrue();
expect($response->json('data.confidence'))->toBeGreaterThan(0.8);
expect($response->json('data.suggestions'))->toBeArray();
})->group('integration');
test('varro erkennt falsche bedeutungen', function () {
$response = postJson('/api/ai/varro/validate', [
'lemma' => 'puella',
'bedeutung' => 'Junge', // Falsche Bedeutung
'wortart' => 'nomen',
'genus' => 'f',
'deklinationsklasse' => 'a',
]);
expect($response)->toBeSuccessfulApiResponse();
expect($response->json('data.is_valid'))->toBeFalse();
expect($response->json('data.issues'))->toContain('bedeutung');
expect($response->json('data.correct_bedeutung'))->toBe('Mädchen');
})->group('integration');
test('varro validiert korrekte verb-einträge', function () {
$response = postJson('/api/ai/varro/validate', [
'lemma' => 'amare',
'bedeutung' => 'lieben',
'wortart' => 'verb',
'konjugationsklasse' => 'a',
]);
expect($response)->toBeSuccessfulApiResponse();
expect($response->json('data.is_valid'))->toBeTrue();
expect($response->json('data.confidence'))->toBeGreaterThan(0.9);
})->group('integration');
test('varro gibt sinnvolle vorschläge bei tippfehlern', function () {
$response = postJson('/api/ai/varro/validate', [
'lemma' => 'discre', // Tippfehler
'bedeutung' => 'lernen',
'wortart' => 'verb',
]);
expect($response)->toBeSuccessfulApiResponse();
expect($response->json('data.is_valid'))->toBeFalse();
expect($response->json('data.suggestions'))->toContain('discere');
})->group('integration');CI/CD-Integration
GitHub Actions Beispiel
yaml
name: Integration Tests
on:
# Manuell triggerbar
workflow_dispatch:
# Wöchentlich am Montag
schedule:
- cron: '0 9 * * 1'
# Vor Releases
push:
tags:
- 'v*'
jobs:
integration-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Install Dependencies
run: composer install
- name: Setup Test Database
run: php artisan test:setup
- name: Run Integration Tests
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: php artisan test --testsuite=IntegrationKosten-Monitoring
Testlauf-Kosten schätzen
php
// In tests/Integration/README.md dokumentieren:
# Geschätzte Kosten pro Testlauf
- **Varro Integration-Tests**: ca. 0.05 EUR (5 Tests, je ~1000 Tokens)
- **Tiro Integration-Tests**: ca. 0.15 EUR (3 Tests, je ~5000 Tokens)
- **Grammaticus Integration-Tests**: ca. 0.08 EUR (4 Tests, je ~2000 Tokens)
**Gesamt pro Testlauf**: ca. 0.28 EUR
**Empfohlene Frequenz**: Wöchentlich oder vor Major-ReleasesLogging für Cost-Tracking
php
test('varro test mit cost-logging', function () {
$startTime = microtime(true);
$response = postJson('/api/ai/varro/validate', [
'lemma' => 'puella',
'bedeutung' => 'Mädchen',
'wortart' => 'nomen',
]);
$duration = microtime(true) - $startTime;
// Token-Usage aus Response loggen
$tokensUsed = $response->json('data.meta.tokens_used');
Log::channel('integration')->info('Varro Test', [
'test' => 'varro validiert korrekte nomen-einträge',
'tokens' => $tokensUsed,
'duration' => $duration,
'cost_estimate' => $tokensUsed * 0.000003, // EUR pro Token (Beispiel)
]);
expect($response)->toBeSuccessfulApiResponse();
})->group('integration');Troubleshooting
Problem: "Test-Datenbank nicht gefunden"
bash
# Lösung: Test-Setup ausführen
php artisan test:setupProblem: "API-Key fehlt"
bash
# Prüfen ob API-Keys in .env.testing gesetzt sind
cat .env.testing | grep ANTHROPIC_API_KEYProblem: "Timeout-Fehler"
php
// Timeout in Test erhöhen
test('langsamer api call', function () {
// ...
})->timeout(120000); // 120 SekundenProblem: "Rate-Limiting"
php
// Sleep zwischen Tests einfügen
test('test 1', function () {
// ...
sleep(2); // 2 Sekunden Pause
})->group('integration');Weitere Ressourcen
- Testing Leitlinien - Allgemeine Test-Richtlinien
- Ordnerstruktur - Test-Verzeichnisstruktur
- TestRunCommand - Smart-Check-Logik
- Pest-Konfiguration - Pest-Setup und Custom Expectations