# Test-Regeln ## Automatische Test-Erweiterung **WICHTIG:** Bei JEDER Code-Aenderung muessen entsprechende Tests erstellt oder aktualisiert werden! ## Wann Tests schreiben? ### IMMER wenn du: 1. **Neue Funktionen** erstellst → Unit Test 2. **Neue API-Endpoints** hinzufuegst → Handler Test 3. **Bugs fixst** → Regression Test (der Bug sollte nie wieder auftreten) 4. **Bestehenden Code aenderst** → Bestehende Tests anpassen ## Test-Struktur ### Go Tests (Consent Service) **Speicherort:** Im gleichen Verzeichnis wie der Code ``` internal/ ├── services/ │ ├── auth_service.go │ └── auth_service_test.go ← Test hier ├── handlers/ │ ├── handlers.go │ └── handlers_test.go ← Test hier └── middleware/ ├── auth.go └── middleware_test.go ← Test hier ``` **Test-Namenskonvention:** ```go func TestFunctionName_Scenario_ExpectedResult(t *testing.T) // Beispiele: func TestHashPassword_ValidPassword_ReturnsHash(t *testing.T) func TestLogin_InvalidCredentials_Returns401(t *testing.T) func TestCreateDocument_MissingTitle_ReturnsError(t *testing.T) ``` **Test-Template:** ```go func TestFunctionName(t *testing.T) { // Arrange service := &MyService{} input := "test-input" // Act result, err := service.DoSomething(input) // Assert if err != nil { t.Fatalf("Expected no error, got %v", err) } if result != expected { t.Errorf("Expected %v, got %v", expected, result) } } ``` **Table-Driven Tests bevorzugen:** ```go func TestValidateEmail(t *testing.T) { tests := []struct { name string email string expected bool }{ {"valid email", "test@example.com", true}, {"missing @", "testexample.com", false}, {"empty", "", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := ValidateEmail(tt.email) if result != tt.expected { t.Errorf("Expected %v, got %v", tt.expected, result) } }) } } ``` ### Python Tests (Backend) **Speicherort:** `/backend/tests/` ``` backend/ ├── consent_client.py ├── gdpr_api.py └── tests/ ├── __init__.py ├── test_consent_client.py ← Tests fuer consent_client.py └── test_gdpr_api.py ← Tests fuer gdpr_api.py ``` **Test-Namenskonvention:** ```python class TestClassName: def test_method_scenario_expected_result(self): pass # Beispiele: class TestConsentClient: def test_check_consent_valid_token_returns_status(self): pass def test_check_consent_expired_token_raises_error(self): pass ``` **Test-Template:** ```python import pytest from unittest.mock import AsyncMock, patch, MagicMock class TestMyFeature: def test_sync_function(self): # Arrange input_data = "test" # Act result = my_function(input_data) # Assert assert result == expected @pytest.mark.asyncio async def test_async_function(self): # Arrange client = MyClient() # Act with patch("httpx.AsyncClient") as mock: mock_instance = AsyncMock() mock.return_value = mock_instance result = await client.fetch_data() # Assert assert result is not None ``` ## Test-Kategorien ### 1. Unit Tests (Hoechste Prioritaet) - Testen einzelne Funktionen/Methoden - Keine externen Abhaengigkeiten (Mocks verwenden) - Schnell ausfuehrbar ### 2. Integration Tests - Testen Zusammenspiel mehrerer Komponenten - Koennen echte DB verwenden (Test-DB) ### 3. Security Tests - Auth/JWT Validierung - Passwort-Hashing - Berechtigungspruefung ## Checkliste vor Abschluss Vor dem Abschluss einer Aufgabe: - [ ] Gibt es Tests fuer alle neuen Funktionen? - [ ] Gibt es Tests fuer alle Edge Cases? - [ ] Gibt es Tests fuer Fehlerfaelle? - [ ] Laufen alle bestehenden Tests noch? (`go test ./...` / `pytest`) - [ ] Ist die Test-Coverage angemessen? ## Tests ausfuehren ```bash # Go - Alle Tests cd consent-service && go test -v ./... # Go - Mit Coverage cd consent-service && go test -cover ./... # Python - Alle Tests cd backend && source venv/bin/activate && pytest -v # Python - Mit Coverage cd backend && pytest --cov=. --cov-report=html ``` ## Beispiel: Vollstaendiger Test-Workflow Wenn du z.B. eine neue `GetUserStats()` Funktion im Go Service hinzufuegst: 1. **Funktion schreiben** in `internal/services/stats_service.go` 2. **Test erstellen** in `internal/services/stats_service_test.go`: ```go func TestGetUserStats_ValidUser_ReturnsStats(t *testing.T) {...} func TestGetUserStats_InvalidUser_ReturnsError(t *testing.T) {...} func TestGetUserStats_NoConsents_ReturnsEmptyStats(t *testing.T) {...} ``` 3. **Tests ausfuehren**: `go test -v ./internal/services/...` 4. **Dokumentation aktualisieren** (siehe [Dokumentation](./documentation.md)) --- ## Modul-spezifische Tests ### Canonical Control Generator (82 Tests) Die Control Library hat eine umfangreiche Test-Suite ueber 6 Dateien. Siehe [Canonical Control Library — Tests](../services/sdk-modules/canonical-control-library.md#tests) fuer Details. ```bash # Alle Generator-Tests cd backend-compliance && pytest -v tests/test_control_generator.py # Similarity Detector Tests cd backend-compliance && pytest -v compliance/tests/test_similarity_detector.py # API Route Tests cd backend-compliance && pytest -v tests/test_canonical_control_routes.py # License Gate Tests cd backend-compliance && pytest -v tests/test_license_gate.py # CI/CD Validator Tests cd backend-compliance && pytest -v tests/test_validate_controls.py ``` **Wichtig:** Die Generator-Tests nutzen Mocks fuer Anthropic-API und Qdrant — sie laufen ohne externe Abhaengigkeiten. Die `TestPipelineMocked`-Klasse prueft insbesondere: - Korrekte Lizenz-Klassifikation (Rule 1/2/3 Verhalten) - Rule 3 exponiert **keine** Quellennamen in `generation_metadata` - SHA-256 Hash-Deduplizierung fuer Chunks - Config-Defaults (`batch_size: 5`, `skip_processed: true`) - Rule 1 Citation wird korrekt mit Gesetzesreferenz generiert