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,227 @@
|
||||
# Testing Standards
|
||||
|
||||
## Coverage
|
||||
|
||||
- **Minimum: 80% Line Coverage** – kein Merge unter 80%
|
||||
- Neue Features: 90%+ Coverage anstreben
|
||||
- Kritische Pfade (Auth, Payment, Data): 95%+
|
||||
|
||||
## Testarten
|
||||
|
||||
| Art | Scope | Framework |
|
||||
|-----|-------|-----------|
|
||||
| Unit | Einzelne Klasse/Funktion | JUnit/pytest/go test/Vitest |
|
||||
| Integration | Mehrere Komponenten | @SpringBootTest/TestClient |
|
||||
| E2E | Ganzer Flow | Playwright/RestAssured |
|
||||
|
||||
## Teststruktur: Gherkin/Given-When-Then
|
||||
|
||||
Alle Testfälle in Given-When-Then Struktur schreiben:
|
||||
|
||||
```java
|
||||
@Test
|
||||
void shouldReturnUserWhenValidIdProvided() {
|
||||
// Given
|
||||
var userId = UUID.randomUUID();
|
||||
var expectedUser = new User(userId, "Max Mustermann");
|
||||
when(userRepository.findById(userId)).thenReturn(Optional.of(expectedUser));
|
||||
|
||||
// When
|
||||
var result = userService.findById(userId);
|
||||
|
||||
// Then
|
||||
assertThat(result).isPresent();
|
||||
assertThat(result.get().getName()).isEqualTo("Max Mustermann");
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
def test_should_return_user_when_valid_id():
|
||||
# Given
|
||||
user_id = uuid4()
|
||||
mock_repo.find_by_id.return_value = User(id=user_id, name="Max")
|
||||
|
||||
# When
|
||||
result = user_service.find_by_id(user_id)
|
||||
|
||||
# Then
|
||||
assert result is not None
|
||||
assert result.name == "Max"
|
||||
```
|
||||
|
||||
## Was testen
|
||||
|
||||
- Happy Path (Normalfall)
|
||||
- Edge Cases (leere Listen, None/null, Grenzwerte)
|
||||
- Error Cases (ungültige Eingaben, Exceptions)
|
||||
- Security (unautorisierter Zugriff, SQL Injection Inputs)
|
||||
|
||||
## Was NICHT testen
|
||||
|
||||
- Getter/Setter ohne Logik
|
||||
- Framework-Code (Spring Boot Auto-Config)
|
||||
- Third-Party Libraries
|
||||
|
||||
## E2E-Tests mit Playwright (nach Deploy auf Preview)
|
||||
|
||||
Wenn das Projekt eine Webapp ist und auf der Preview-Umgebung deployed wurde:
|
||||
|
||||
### Preview-URL
|
||||
|
||||
```
|
||||
https://{app-name}-{namespace}.${ART_NAME}-iat.cnp-test.comp.db.de
|
||||
```
|
||||
|
||||
### E2E-Tests durchführen
|
||||
|
||||
Nutze den Playwright MCP Server (ist im Pod verfügbar):
|
||||
|
||||
1. Zur Preview-URL navigieren
|
||||
2. Seite laden, prüfen ob Grundfunktionen da sind
|
||||
3. Formulare ausfüllen, Buttons klicken
|
||||
4. Responses/Ergebnisse prüfen
|
||||
5. Screenshots als Evidenz
|
||||
|
||||
### Beispiel-Prüfungen
|
||||
|
||||
- Startseite lädt ohne Fehler
|
||||
- CRUD-Operationen funktionieren (Erstellen, Lesen, Bearbeiten, Löschen)
|
||||
- Validierung greift (leere Felder, ungültige Eingaben)
|
||||
- API-Endpoints antworten korrekt (JSON-Response prüfen)
|
||||
|
||||
### Screenshots im MR
|
||||
|
||||
Relevante Screenshots als Kommentar am MR anhängen oder in der MR-Description referenzieren.
|
||||
|
||||
### Akzeptanzkriterien in Gherkin
|
||||
|
||||
Testfälle als Gherkin-Szenarien. Wenn in der Aufgabe bereits Gherkin-Szenarien formuliert sind → direkt übernehmen. Sonst selbst aus der Anforderung ableiten.
|
||||
|
||||
```gherkin
|
||||
Feature: Adressverwaltung
|
||||
|
||||
Scenario: Neue Adresse anlegen
|
||||
Given ich bin auf der Startseite
|
||||
When ich auf "Neue Adresse" klicke
|
||||
And ich das Formular ausfülle:
|
||||
| Feld | Wert |
|
||||
| Name | Max Mustermann |
|
||||
| Straße | Musterstr. 1 |
|
||||
| Stadt | Berlin |
|
||||
| PLZ | 10115 |
|
||||
| Land | Deutschland |
|
||||
And ich auf "Speichern" klicke
|
||||
Then sehe ich "Max Mustermann" in der Adressliste
|
||||
|
||||
Scenario: Validierung bei leerem Namen
|
||||
Given ich bin auf der Startseite
|
||||
When ich auf "Neue Adresse" klicke
|
||||
And ich das Formular ohne Name absende
|
||||
Then sehe ich eine Fehlermeldung
|
||||
|
||||
Scenario: Adresse löschen
|
||||
Given es existiert eine Adresse "Max Mustermann"
|
||||
When ich auf "Löschen" klicke
|
||||
Then ist "Max Mustermann" nicht mehr in der Liste
|
||||
```
|
||||
|
||||
### Ablauf
|
||||
|
||||
1. Gherkin-Szenarien aus der Aufgabe ableiten
|
||||
2. In GitLab Issue als Akzeptanzkriterien dokumentieren
|
||||
3. Nach Deploy: Szenarien mit Playwright gegen Preview-URL ausführen
|
||||
4. Jedes Szenario = ein Playwright-Test (navigieren, klicken, prüfen)
|
||||
5. Bei Fehler: Screenshot + Beschreibung als MR-Kommentar
|
||||
|
||||
## Load-Testing mit hey
|
||||
|
||||
Nach erfolgreichem E2E-Test: Einfachen Last-Test gegen die Preview-URL fahren.
|
||||
|
||||
### Wann Load-Testing
|
||||
|
||||
- Bei REST APIs mit erwarteter Last
|
||||
- Bei Endpoints die Datenbank-Zugriffe machen
|
||||
- Nicht bei reinen Doku-Projekten oder Libraries
|
||||
|
||||
### Verwendung
|
||||
|
||||
```bash
|
||||
# Einfacher GET-Test: 200 Requests, 10 parallel
|
||||
hey -n 200 -c 10 http://preview-url/api/addresses
|
||||
|
||||
# POST mit Body und Auth
|
||||
hey -n 100 -c 5 \
|
||||
-m POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-d '{"name":"Load Test","street":"Teststr. 1","city":"Berlin","zip":"10115","country":"DE"}' \
|
||||
http://preview-url/api/addresses
|
||||
|
||||
# PUT (Update)
|
||||
hey -n 100 -c 5 \
|
||||
-m PUT \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"name":"Updated"}' \
|
||||
http://preview-url/api/addresses/1
|
||||
```
|
||||
|
||||
### Auswertung
|
||||
|
||||
hey gibt aus:
|
||||
- Response-Zeiten (avg, p50, p95, p99)
|
||||
- Throughput (Requests/sec)
|
||||
- Status-Code-Verteilung
|
||||
- Fehlerrate
|
||||
|
||||
### Akzeptanzkriterien (Richtwerte)
|
||||
|
||||
- p95 Response-Zeit < 500ms
|
||||
- Fehlerrate < 1%
|
||||
- Keine 5xx Errors unter Last
|
||||
|
||||
### Ergebnis dokumentieren
|
||||
|
||||
Load-Test-Ergebnisse als Kommentar am MR oder in Session-Notes festhalten.
|
||||
Wenn Ergebnisse schlecht: Performance-Issue anlegen.
|
||||
|
||||
## Integration Tests mit Testcontainers
|
||||
|
||||
Für Integration Tests mit echten Datenbanken/Services: [testcontainers.org](https://testcontainers.org)
|
||||
|
||||
### Verwendung
|
||||
|
||||
```java
|
||||
@SpringBootTest
|
||||
@Testcontainers
|
||||
class UserRepositoryIT {
|
||||
|
||||
@Container
|
||||
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
|
||||
|
||||
@DynamicPropertySource
|
||||
static void configureProperties(DynamicPropertyRegistry registry) {
|
||||
registry.add("spring.datasource.url", postgres::getJdbcUrl);
|
||||
registry.add("spring.datasource.username", postgres::getUsername);
|
||||
registry.add("spring.datasource.password", postgres::getPassword);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSaveAndFindUser() {
|
||||
// Given-When-Then
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Im Agent-Pod
|
||||
|
||||
- Podman ist im Base-Image installiert (Testcontainers-kompatibel)
|
||||
- Env-Variablen für Testcontainers mit Podman sind gesetzt:
|
||||
- `TESTCONTAINERS_RYUK_DISABLED=true`
|
||||
- `DOCKER_HOST=unix:///run/podman/podman.sock`
|
||||
|
||||
### Wann Testcontainers nutzen
|
||||
|
||||
- Repository-Tests mit echter DB (statt H2)
|
||||
- Kafka-Integration Tests
|
||||
- Tests gegen externe Services (Wiremock-Container)
|
||||
- NICHT für Unit-Tests (dort Mocks verwenden)
|
||||
Reference in New Issue
Block a user