Migrate all repos into monorepo context folders
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.
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
---
|
||||
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
|
||||
Reference in New Issue
Block a user