Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)
Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
257 lines
7.3 KiB
Markdown
257 lines
7.3 KiB
Markdown
---
|
|
inclusion: manual
|
|
---
|
|
|
|
# Unit Tests schreiben
|
|
|
|
> **Nutzung:** Referenziere diese Datei mit `#unit-tests-motivation` im Chat und sage:
|
|
> "Schreibe Unit Tests für [Komponente/Klasse/Funktion] nach diesem Leitfaden."
|
|
|
|
---
|
|
|
|
## Ziel
|
|
Effektive Anleitung für LLMs zur Erstellung qualitativ hochwertiger Unit Tests mit klaren Erwartungen und Best Practices.
|
|
|
|
## Motivation & Kontext
|
|
|
|
Erhöhe die Unit-Test-Abdeckung im Projekt.
|
|
|
|
- Ziel: Schreibe Unit-Tests (JUnit 5) für das Projekt, sodass die gesamte Code Coverage auf mindestens 80% steigt.
|
|
- Einschränkungen (nicht ändern):
|
|
- Verändere keinen Produktionscode unter `src/main/java`.
|
|
- Verändere keine vorhandenen Tests unter `src/test/java`.
|
|
- Verändere keine bestehenden Quell-Dateinamen oder APIs.
|
|
- Keine Netzwerke/DBs in Unit-Tests; externe Abhängigkeiten nur mocken.
|
|
|
|
- Erlaubt:
|
|
- Neue Testklassen und Test-Hilfsklassen unter `src/test/java` anlegen.
|
|
- Test-spezifische Ressourcen unter `src/test/resources`.
|
|
|
|
- Anforderungen an Tests:
|
|
- Nutze JUnit 5 (`@Test`), Moq/Mockito für Abhängigkeiten.
|
|
- Tests sollen deterministisch, schnell und isoliert sein.
|
|
- Jede getestete Klasse sollte sinnvolle Positive-/Negative-/Randfall-Tests bekommen.
|
|
- Benenne Tests nach der vorhandenen Nomenklatur.
|
|
|
|
- Verifizierung (Automatisierte Checks):
|
|
1. Build: Projekt baut erfolgreich (Exit-Code 0). Kommando: `mvn test`.
|
|
2. Tests: Alle Tests laufen grün (keine Failures/Errors).
|
|
3. Coverage: Generiere Coverage-Report (mvn jacoco:report). Akzeptanz: Gesamte Projekt-Coverage >= 80% (Line Coverage). Report-Pfad: `target/site/jacoco/index.html`.
|
|
|
|
- Zusätzliche Hinweise:
|
|
- Keine Refactorings am Produktionscode.
|
|
- Falls ein Test-only Helper oder Fixture nötig ist, lege diese ausschließlich unter `src/test/java` an.
|
|
|
|
## Constraints
|
|
|
|
**Du MUST:**
|
|
- Tests für alle öffentlichen Methoden/Funktionen schreiben
|
|
- Sowohl positive als auch negative Testfälle abdecken
|
|
- Aussagekräftige Testnamen verwenden, die das erwartete Verhalten beschreiben
|
|
- Arrange-Act-Assert (AAA) Pattern befolgen
|
|
- Tests isoliert und unabhängig voneinander halten
|
|
- Mocks/Stubs für externe Abhängigkeiten verwenden
|
|
|
|
**Du SHOULD:**
|
|
- Edge Cases und Grenzwerte testen
|
|
- Fehlerbehandlung und Exception-Szenarien abdecken
|
|
- Parametrisierte Tests für ähnliche Testfälle nutzen
|
|
- Test-Fixtures und Setup-Methoden sinnvoll einsetzen
|
|
|
|
**Du MUST NOT:**
|
|
- Tests schreiben, die von externen Ressourcen abhängen (Datenbank, Netzwerk, Dateisystem)
|
|
- Tests erstellen, die eine bestimmte Ausführungsreihenfolge erfordern
|
|
- Implementation Details testen statt Verhalten
|
|
- Produktionscode unter `src/main/java` verändern
|
|
- Bestehende Tests unter `src/test/java` modifizieren
|
|
|
|
## Test-Struktur
|
|
|
|
### Namenskonvention
|
|
```
|
|
[MethodName]_[Scenario]_[ExpectedBehavior]
|
|
```
|
|
|
|
Beispiele:
|
|
- `calculateTotal_WithValidItems_ReturnsCorrectSum`
|
|
- `processPayment_WithInsufficientFunds_ThrowsException`
|
|
- `getUserById_WhenUserNotFound_ReturnsNull`
|
|
|
|
### AAA Pattern
|
|
```java
|
|
@Test
|
|
void testMethodName_Scenario_ExpectedBehavior() {
|
|
// Arrange - Setup test data and dependencies
|
|
[Test-Setup]
|
|
|
|
// Act - Execute the method under test
|
|
[Methodenaufruf]
|
|
|
|
// Assert - Verify the expected outcome
|
|
[Assertions]
|
|
}
|
|
```
|
|
|
|
## Testabdeckung
|
|
|
|
### Prioritäten
|
|
1. **Kritische Geschäftslogik** - Kernfunktionalität mit hohem Risiko
|
|
2. **Komplexe Algorithmen** - Berechnungen, Transformationen, Validierungen
|
|
3. **Fehlerbehandlung** - Exception-Handling, Validierung
|
|
4. **Edge Cases** - Grenzwerte, null/empty, unerwartete Eingaben
|
|
5. **Integration Points** - Schnittstellen zu anderen Komponenten
|
|
|
|
### Mindestabdeckung
|
|
- **Gesamtprojekt:** 80%+ Line Coverage (Ziel)
|
|
- **Kritische Komponenten:** 90%+ Code Coverage
|
|
- **Standard-Komponenten:** 80%+ Code Coverage
|
|
|
|
## Technologie-spezifische Guidelines
|
|
|
|
### JUnit 5 + Mockito
|
|
```java
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
import org.mockito.Mock;
|
|
import org.mockito.MockitoAnnotations;
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
import static org.mockito.Mockito.*;
|
|
|
|
class ServiceTest {
|
|
|
|
@Mock
|
|
private Dependency mockDependency;
|
|
|
|
private Service service;
|
|
|
|
@BeforeEach
|
|
void setUp() {
|
|
MockitoAnnotations.openMocks(this);
|
|
service = new Service(mockDependency);
|
|
}
|
|
|
|
@Test
|
|
void methodName_Scenario_ExpectedBehavior() {
|
|
// Arrange
|
|
when(mockDependency.someMethod()).thenReturn(expectedValue);
|
|
|
|
// Act
|
|
Result result = service.methodUnderTest();
|
|
|
|
// Assert
|
|
assertNotNull(result);
|
|
assertEquals(expectedValue, result.getValue());
|
|
verify(mockDependency).someMethod();
|
|
}
|
|
}
|
|
```
|
|
|
|
## Beispiele
|
|
|
|
### Beispiel 1: Einfacher Unit Test
|
|
```java
|
|
@Test
|
|
void add_TwoPositiveNumbers_ReturnsSum() {
|
|
// Arrange
|
|
Calculator calculator = new Calculator();
|
|
|
|
// Act
|
|
int result = calculator.add(5, 3);
|
|
|
|
// Assert
|
|
assertEquals(8, result);
|
|
}
|
|
```
|
|
|
|
### Beispiel 2: Test mit Mocks
|
|
```java
|
|
@Test
|
|
void processOrder_ValidOrder_CallsPaymentService() {
|
|
// Arrange
|
|
Order order = new Order(100.0);
|
|
when(mockPaymentService.charge(100.0)).thenReturn(true);
|
|
|
|
// Act
|
|
boolean result = orderProcessor.process(order);
|
|
|
|
// Assert
|
|
assertTrue(result);
|
|
verify(mockPaymentService).charge(100.0);
|
|
}
|
|
```
|
|
|
|
### Beispiel 3: Exception Test
|
|
```java
|
|
@Test
|
|
void divide_ByZero_ThrowsArithmeticException() {
|
|
// Arrange
|
|
Calculator calculator = new Calculator();
|
|
|
|
// Act & Assert
|
|
assertThrows(ArithmeticException.class, () -> {
|
|
calculator.divide(10, 0);
|
|
});
|
|
}
|
|
```
|
|
|
|
## Häufige Fehler vermeiden
|
|
|
|
| Fehler | Lösung |
|
|
|--------|--------|
|
|
| Tests testen Implementation statt Verhalten | Fokus auf öffentliche API und erwartete Ergebnisse |
|
|
| Zu viele Assertions pro Test | Ein Test = Ein Konzept/Verhalten |
|
|
| Fragile Tests durch harte Abhängigkeiten | Dependency Injection und Mocking nutzen |
|
|
| Unklare Fehlermeldungen | Aussagekräftige Assert-Messages verwenden |
|
|
| Tests ohne Arrange-Phase | Immer explizites Setup, auch wenn minimal |
|
|
| Produktionscode ändern | Nur Tests unter `src/test/java` anlegen |
|
|
|
|
## Checkliste
|
|
|
|
Vor dem Abschluss prüfen:
|
|
- [ ] Alle öffentlichen Methoden haben Tests
|
|
- [ ] Positive und negative Szenarien abgedeckt
|
|
- [ ] Edge Cases berücksichtigt
|
|
- [ ] Testnamen sind selbsterklärend
|
|
- [ ] Tests sind unabhängig und isoliert
|
|
- [ ] Keine externen Abhängigkeiten
|
|
- [ ] AAA-Pattern konsequent angewendet
|
|
- [ ] Code Coverage Ziel (80%) erreicht
|
|
- [ ] `mvn test` läuft erfolgreich durch
|
|
- [ ] Kein Produktionscode verändert
|
|
|
|
## Verifizierung
|
|
|
|
### Build & Test ausführen
|
|
```bash
|
|
mvn test
|
|
```
|
|
|
|
### Coverage Report generieren
|
|
```bash
|
|
mvn jacoco:report
|
|
```
|
|
|
|
### Coverage Report prüfen
|
|
```bash
|
|
# Report-Pfad: target/site/jacoco/index.html
|
|
# Ziel: >= 80% Line Coverage
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Tests schlagen fehl
|
|
- Prüfe ob Mocks korrekt konfiguriert sind
|
|
- Verifiziere Test-Daten und erwartete Werte
|
|
- Stelle sicher, dass Tests isoliert laufen
|
|
|
|
### Niedrige Code Coverage
|
|
- Identifiziere ungetestete Branches mit Jacoco-Report
|
|
- Füge Tests für Exception-Handling hinzu
|
|
- Teste Edge Cases und Grenzwerte
|
|
- Prüfe ob alle öffentlichen Methoden getestet sind
|
|
|
|
### Langsame Tests
|
|
- Ersetze echte Abhängigkeiten durch Mocks
|
|
- Vermeide Thread.sleep() und Timeouts
|
|
- Nutze In-Memory Implementierungen
|