Table of Contents
- Tests
- Überblick: Welche Arten von Tests gibt es?
- Voraussetzungen
- Tests ausführen
- 1) Hauptsuite: run-tests.php
- 2) Assertion-Selbsttest: assertion-validation.php
- 3) Mutationstests: validate-tests.php (Meta-Test)
- Meta-Tests gezielt überspringen
- Was wird getestet? (Abdeckung im Detail)
- ConfigRepository
- RegistrationRepository
- AuthService (Admin-Auth)
- CSRFService
- MailQueueRepository (Queue-Mechanik)
- MailService (Templates, ohne echte Mails)
- Counter-Logik (fachliche Berechnungen)
- Repository::CreatePDO (Edge Cases)
- Artefakte / Cleanup
- Troubleshooting
- Empfehlungen für Erweiterungen (für Contributors)
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Tests
Diese Seite dokumentiert die implementierten Tests im Code-Repo (zgb_www/tests/) ausführlich: Aufbau, Ausführung, Abdeckung und typische Stolperstellen.
Überblick: Welche Arten von Tests gibt es?
Das Projekt nutzt kein PHPUnit. Stattdessen gibt es:
- Integrationstests (Runner):
zgb_www/tests/run-tests.php- prüft zentrale Repository- und Service-Funktionen gegen eine echte SQLite-Testdatenbank
- Assertion-Selbsttest:
zgb_www/tests/assertion-validation.php- prüft, ob die im Runner verwendeten
assert*()-Hilfsfunktionen korrekt arbeiten
- prüft, ob die im Runner verwendeten
- Test-Validierung (Mutationstests):
zgb_www/tests/validate-tests.php- Ziel: prüfen, ob Tests Code-Änderungen wirklich erkennen
- Achtung: verändert temporär Quellcode-Dateien (mit Backup/Restore)
- verwendet
tests/bootstrap.php(shared bootstrap, keine PHPUnit-Abhängigkeit)
Zusätzliche Dokumente:
zgb_www/tests/TEST-VALIDATION-REPORT.md: zusammenfassender Bericht zur Test-Qualität/Abdeckungzgb_www/tests/test-review.md: manuelle Review-Notizen zu den Tests
Voraussetzungen
Für die Tests wird benötigt:
- PHP 8+
- Extension
pdo_sqlite - Schreibrechte im Repo, da Test-DBs/Backups erzeugt werden:
zgb_www/test_data/(Test-DB Dateien)zgb_www/test_backups/(Backups für Mutationstests)
Tests ausführen
1) Hauptsuite: run-tests.php
Aus dem Repo-Root:
php tests/run-tests.php
Verhalten:
- gibt pro Test
✓(PASS) oder✗(FAIL) aus - Exit-Code:
0wenn alle Tests bestehen1wenn mindestens ein Test fehlschlägt
Standardmäßig führt der Runner nach den Integrationstests auch Meta-Tests aus:
- Assertion-Validierung (
assertion-validation.php) - Mutationstests (
validate-tests.php)
Das erhöht die Laufzeit, aber verbessert die Aussagekraft (“testen die Tests wirklich?”).
Technik:
- jeder Test erzeugt eine eigene SQLite-Datei in
test_data/(uniqid()im Dateinamen) - die Datei wird am Ende (best effort) gelöscht
- Session wird im CLI-Kontext so konfiguriert, dass es keine Cookie-Warnungen gibt
2) Assertion-Selbsttest: assertion-validation.php
php tests/assertion-validation.php
Das Script führt negative Tests aus (z.B. assertTrue(false) muss eine Exception werfen) und beendet sich mit:
0wenn alle Assertions korrekt funktionieren1wenn eine Assertion “falsch” implementiert wäre
3) Mutationstests: validate-tests.php (Meta-Test)
Zweck: Absicherung, dass Tests nicht “grün” sind, obwohl die Software kaputt ist.
Dazu wird Code absichtlich manipuliert (“Mutation”), danach wird run-tests.php ausgeführt und es wird erwartet, dass die Tests fehlschlagen.
Wenn/ sobald lauffähig, gilt:
- Es erzeugt Backups in
test_backups/und stellt sie nach jedem Mutationsdurchlauf wieder her. - Es führt u.a. diese Mutationen durch:
ConfigRepository::loadConfig()liefert absichtlich falschesstartDateRegistrationRepository::saveRegistration()speichert “nicht”AuthService::login()setztis_adminnicht
Warnung: Mutationstests ändern Dateien in zgb-backend/ temporär.
Nicht auf einem Shared-Checkout laufen lassen und nicht parallel zu anderen Prozessen.
Meta-Tests gezielt überspringen
Wenn du nur die Integrationstests laufen lassen willst (z.B. wenn du selbst gerade an validate-tests.php arbeitest),
kannst du Meta-Tests überspringen:
php tests/run-tests.php --skip-meta
Hinweis: validate-tests.php nutzt intern ebenfalls --skip-meta, um Rekursion zu vermeiden.
Was wird getestet? (Abdeckung im Detail)
Die folgenden Punkte beziehen sich auf tests/run-tests.php.
ConfigRepository
Abgedeckt:
loadConfig()liefert einConfig-Objekt und hat Default-WertesaveConfig()persistiert Werte, die wieder geladen werden könnensetConfig()/getConfig()für einzelne Keys (inkl. “Key not found” Exception)pdo()Getter gibt die verwendete PDO-Instanz zurück
Warum relevant:
- Config ist zentral (Anmeldezeitraum, Nummernrange, operatorEmail, eventDate, Admin-Passwort-Hash, Mail-Queue-Keys)
RegistrationRepository
Abgedeckt:
saveRegistration()+getAllRegistrations()RoundtriploadRegistration(id)liefert Objekt odernull(nicht existierende ID)- UNIQUE-Constraint: doppelte
numberwird verhindert (PDOException) existsDuplicateRegistration()erkennt Duplikate auf Kerndaten (und erkennt Nicht-Duplikate)teamMemberwird korrekt gespeichert/geladen- Validierungsfunktionen:
isNumberValidAndAvailable(number, start, end)(Bereich + Verfügbarkeit)getFirstFreeNumber(start, end)liefertnullbei vollem Kontingent- Verhalten bei “Lücken” in der Nummernfolge
Warum relevant:
- Nummernlogik und Duplikatlogik sind kritisch für die Anmeldung unter Last.
AuthService (Admin-Auth)
Abgedeckt:
login()/logout()/isAdmin()(Session-Flag)- Rate-Limit:
failRateLimit()erhöht counter,resetRateLimit()setzt zurück
Einschränkung:
- Funktionen, die
exit()ausführen (z.B.requireAdmin()odercheckRateLimit()im Block-Fall), sind nur indirekt testbar; der Test prüft deshalb v.a. Voraussetzungen und Session-State.
CSRFService
Abgedeckt:
getToken()erzeugt Token (64 hex chars = 32 bytes)- Token bleibt innerhalb TTL gleich
checkToken(token)akzeptiert gültige Tokens und wirft bei ungültigenrotateToken()erzeugt neuen Token- TTL-Ablauf: Session-Zeitstempel wird im Test künstlich “alt” gesetzt und geprüft, dass neuer Token entsteht
Warum relevant:
- Admin-POSTs und Registrierungs-POST sind CSRF-geschützt; Token-/TTL-Verhalten ist sicherheitskritisch.
MailQueueRepository (Queue-Mechanik)
Abgedeckt:
enqueue()ist idempotent (doppeltes Enqueue → kein doppelter Job)claimNextJobs()claimt Jobs unddeleteJob()räumt erfolgreich gesendete Jobs weg (“Option A”)recoverStuckSending()setzt Jobs nach abgelaufenem Lock wieder zurück
Hinweis:
- Der Worker (
MailQueueWorker) selbst wird im Runner nicht als End-to-End “send loop” getestet (kein echter Mailversand). Die wichtigsten Datenbank-Operationen sind aber abgedeckt.
MailService (Templates, ohne echte Mails)
Abgedeckt:
- Template-Datei existiert und enthält Platzhalter
- einfache Platzhalter-Ersetzung im Test (ohne echten
mail()Aufruf)
Warum so:
- Echten Mailversand zu testen ist ohne Mock/Abstraktion schwierig und in CI meist unerwünscht.
Counter-Logik (fachliche Berechnungen)
Abgedeckt:
- “ohne Registrierungen”
- “mit vielen Registrierungen”
- “volles Kontingent”
Hinweis:
- Das ist eine Logikprüfung innerhalb des Tests (keine direkte Ausführung von
counter.phpals HTTP-Request).
Repository::CreatePDO (Edge Cases)
Abgedeckt:
- Verhalten bei “ungültigem Pfad” ist OS-abhängig (Windows kann Verzeichnisse ggf. erzeugen). Der Test akzeptiert daher entweder “funktioniert” oder “wirft eine sinnvolle Exception”.
Artefakte / Cleanup
Die Tests erzeugen Dateien:
zgb_www/test_data/test_*.db(sollten nach jedem Test gelöscht werden)zgb_www/test_backups/*.backup(für Mutationstests)
Wenn Tests hart abbrechen (z.B. Ctrl+C), können Dateien liegen bleiben – dann einfach den Ordner test_data/ bereinigen.
Troubleshooting
pdo_sqlitefehlt: Runner warnt; DB-Tests werden fehlschlagen.- DB-Datei lässt sich nicht löschen (v.a. Windows): Prozess hält ggf. noch einen Handle.
Tipp: Testlauf beenden, kurz warten, erneut probieren; ggf. prüfen, ob ein PHP-Prozess noch läuft. - Session-Warnungen: Der Runner nutzt Output-Buffering und setzt Session-Inis für CLI; falls dennoch Warnungen erscheinen, ist oft eine PHP-Konfiguration ungewöhnlich.
Empfehlungen für Erweiterungen (für Contributors)
- Neue Tests bevorzugt als zusätzliche
runTest('Name', function() { ... })Blöcke inrun-tests.php, isoliert mit eigener Test-DB. - Keine externen Side-Effects (keine echten Mails, keine echten Netzwerkzugriffe).
- Bei Code, der
exit()aufruft: entweder Zustand vorexit()prüfen oder (optional) den Code refactoren, um testbarer zu werden (z.B. Exceptions stattexit()in Kernlogik).
Einstieg
Architektur
- Architektur-Übersicht
- Frontend-Build
- Backend
- Datenbank
- Mail-Queue
- Performance & Optimierungen
- Entscheidungen & Historie
Betrieb
Projektarbeit
- Code:
ssh://forgejo@home.schumbi.de/ralf/zgb_www.git - Wiki:
ssh://forgejo@home.schumbi.de/ralf/zgb_www.wiki.git