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.
228 lines
6.1 KiB
Markdown
228 lines
6.1 KiB
Markdown
# 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)
|