meldestelle/docs/06_Frontend/Teststrategie_Desktop.md

185 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

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.

# 🧐 QA Test-Strategie — Compose Desktop App
> Stand: 2. April 2026
> Gültig für: Kotlin Multiplatform / Compose Desktop (JVM) Frontend
---
## Ziel
Konsistente, schnelle und verlässliche Tests für die Desktop-App. Diese Richtlinie definiert die Testpyramide, das Tooling und verbindliche Konventionen (Benennung, Ordnerstruktur, ArrangeActAssert), damit Frontend, QA und DevOps nahtlos zusammenarbeiten können.
---
## Testpyramide für Compose Desktop
1) Unit-Tests (7080%)
- Reine Kotlin-Logik ohne UI: ViewModels, Reducer/Intent-Handler, Mapper/Formatter, Validatoren
- Keine echten I/OOperationen, keine echten Uhren/Dispatcher → alles gemockt oder gefaked
- Laufzeit: < 100 ms pro Test, parallelisierbar
2) Integrations-Tests (1525%)
- Zusammenspiel mehrerer Komponenten auf JVM (z. B. ViewModel + Repository mit InMemory/Fake Datenquelle)
- Optionale Nutzung eines Test-Dispatchers; kein echtes Netzwerk/Dateisystem
- Ziel: Korrekte State-Transitions, Fehlerpfade, Laden/SpeichernFlows
3) UI-Tests (510%)
- Compose UI Test Framework (Desktop): Semantics-basierte Interaktion und Assertions
- Abdecken kritischer User-Flows (Happy Path + 12 Edge Cases)
- Headless-fähig für CI (Xvfb/JetBrains Runtime Headless). Kürzere, robuste Tests (keine Pixel-Assertions)
Leitprinzip: So viel wie möglich unterhalb der UI testen (schnell/stabil), nur kritische End-to-EndFlows als UI-Test absichern.
---
## Tooling-Entscheidung
- Test-Framework: `kotlin.test`
- Einheitlich über KMP, minimaler Overhead, gute IDE/CI-Integration
- Mocking/Stubs: `MockK`
- Kotlinfreundlich, unterstützt Klassen/Objekte, klare Verifikation von Interaktionen
- Coroutines/Flows testen: `kotlinx-coroutines-test`
- `StandardTestDispatcher`, `runTest {}`, virtuelle Zeitsteuerung, deterministische Tests
- UI-Tests: Compose UI Test (Desktop)
- `compose.ui.test` APIs: `onNodeWithText`, `performClick`, `assertIsDisplayed`, etc.
- Headless in CI via JVM Args/Virtual Display (DevOps setzt Runner bereit)
- Optional (nur falls notwendig):
- Snapshot-Testing vermeiden (fragil im Desktop-Kontext)
- Property-based Testing optional (z. B. mit Kotest property) nicht Standard
---
## Ordner- und Modulstruktur (KMP/Compose Desktop)
Beispielhaft; bitte auf bestehende Modulnamen im Repo mappen:
- `frontend/` (Wurzel des KMP-Frontends)
- `commonMain/` UI-agnostische Logik, Models, Use-Cases, Validatoren
- `commonTest/` Unit- und Integrations-Tests für Common
- `desktopMain/` Desktop-spezifische UI (Compose Desktop) und Integrationscode
- `desktopTest/` UI-Tests (Compose UI Test) und Desktop-Integrations-Tests
Konvention:
- Business-/State-Logik so weit wie möglich in `commonMain` halten maximaler Anteil schneller Unit-Tests in `commonTest`.
- UI-spezifische Tests in `desktopTest` nur für kritische End-to-EndFlows.
---
## Benennungs- und Strukturkonventionen
- Test-Klassenname: `<ProduktionsKlasse>Test.kt` oder `<Feature/UseCase>Test.kt`
- Test-Funktionsname (kotlin.test): ``fun `<Methode/Intent>_<Bedingung>_<ErwartetesVerhalten>()``
- Beispiel: ``fun `onSave_withInvalidInput_emitsValidationError`()``
- ArrangeActAssert (AAA) strikt einhalten:
- Arrange: Testdaten, Mocks, System Under Test (SUT) erstellen
- Act: eine gezielte Aktion / Intent ausführen
- Assert: erwarteten Zustand/Ereignisse prüfen
- Given/When/Then als Kommentare optional:
- `// Given`, `// When`, `// Then` keine unnötigen Kommentare, nur zur Struktur
- Ordner nach Domäne/Feature gruppieren (bevorzugt):
- `commonTest/<feature>/...`, `desktopTest/<flow>/...`
---
## Coroutines & State-Tests (Beispiel)
```kotlin
import kotlin.test.*
import kotlinx.coroutines.test.*
class AnmeldungViewModelTest {
@Test
fun `onWeiter_withEmptyPflichtfeld_emitsValidationError`() = runTest {
// Arrange
val vm = AnmeldungViewModel(/* fakes */)
// Act
vm.onWeiter()
// Assert
assertTrue(vm.state.value.validationErrorShown)
}
}
```
---
## Compose UI Test (Desktop) — Grundsätze
- Selektoren über Semantics (Text, ContentDescription, TestTags via `Modifier.testTag("…")`)
- Keine Fragilität: Keine Pixel-/Layoutabhängigen Asserts
- Jeder UI-Test prüft genau einen kritischen Flow, Laufzeitziel < 3s pro Test
Minimalbeispiel:
```kotlin
import androidx.compose.ui.test.*
import kotlin.test.Test
class NennungUiTest {
@Test
fun startliste_filterByBewerb_showsOnlyMatchingEntries() {
// Given
val rule = createComposeRule()
rule.setContent { AppRoot() }
// When
rule.onNodeWithTag("filter-bewerb").performClick()
rule.onNodeWithText("CSN-C-NEU 95cm").performClick()
// Then
rule.onAllNodesWithTag("startlisten-zeile")
.assertCountEquals( /* erwartete Anzahl */ 5)
}
}
```
Hinweis: Die konkrete Setup-/Runner-Konfiguration für Headless-Ausführung wird in `docs/07_Infrastructure/ci-testing.md` (DevOps) dokumentiert.
---
## Testdaten und Fakes
- Fakes statt Mocks, wenn Verhalten wichtiger als Interaktion ist (z. B. InMemoryRepository)
- Test-Datenbuilder verwenden (kleine DSLs / Fabriken) statt anonymer Maps/Listen
- Zeitabhängiges Verhalten: `TestCoroutineScheduler` + injizierbare Clock/NowProvider
---
## Qualitätsregeln für Tests
- Stabilität > Vollständigkeit: flaky Tests sind zu entfernen oder neu zu schneiden
- Ein Test ein Verhalten: keine überladenen Tests
- Determinismus: keine versteckten Sleeps/Delays, virtuelle Zeit nutzen
- Lesbarkeit: AAA, sprechende Namen, knappe ArrangeBlöcke
---
## CI/CDIntegration (Kurz)
- Unit/Integrations: JVM headless, parallel (Gradle `--parallel`), `-Dkotlinx.coroutines.scheduler.keep.alive.sec=…` falls nötig
- UI: Headless via Xvfb oder JBR Headless; kurzer SmokeSatz ausführen
- Reports: Gradle HTML/JUnit XML; Flaky-Tracking über CI möglich
---
## Checkliste (DoD)
- [ ] Neuer Test folgt AAA und Namenskonvention
- [ ] Läuft headless lokal und in CI
- [ ] Keine externen Abhängigkeiten ohne Fake/Mock
- [ ] UI-Test nutzt Semantics/TestTags und ist robust
---
## Verweise
- Roadmap: `docs/04_Agents/Roadmaps/QA_Roadmap.md` (Punkt A-1)
- DevOps (Headless/CI): `docs/07_Infrastructure/` (geplantes Dokument `ci-testing.md`)