Testing¶
TCM365 pflegt eine umfassende Test-Suite mit Backend Unit Tests, Cross-Tenant Isolation Tests und Frontend End-to-End Tests. Dieser Guide erklaert die Test-Infrastruktur, Patterns und Konventionen.
Übersicht¶
| Bereich | Framework | Anzahl Tests | Coverage-Fokus |
|---|---|---|---|
| Backend Unit | Jest 29.7 | 780+ | Services, Adapter, Utilities, Entities |
| Cross-Tenant | Jest 29.7 | 70+ | Tenant-Isolation und IDOR-Prävention |
| Frontend E2E | Playwright | -- | Benutzerflows und API Integration |
Backend Testing¶
Test Framework¶
Das Backend verwendet Jest 29.7 mit ts-jest für TypeScript Unterstützung. Die Konfiguration befindet sich in backend-js/jest.config.js (oder package.json).
Tests ausführen¶
cd backend-js
# Alle Tests ausführen
npm test
# Tests im Watch-Modus (re-run bei Dateiänderungen)
npm run test:watch
# Tests mit Coverage Report
npm run test:cov
# Spezifische Testdatei ausführen
npx jest src/modules/snapshots/snapshots.service.spec.ts
# Tests nach Pattern filtern
npx jest --testPathPattern="baselines"
# End-to-End Tests
npm run test:e2e
Testdatei-Organisation¶
Testdateien befinden sich neben den Quelldateien, die sie testen (NestJS Konvention):
modules/snapshots/
├── snapshots.service.ts # Implementation
├── snapshots.service.spec.ts # Unit Tests
├── snapshots.controller.ts # Controller
└── dto/
└── create-snapshot.dto.ts
Spec-Dateien¶
Die folgenden Spec-Dateien decken die Kernmodule und Services ab:
| Spec-Datei | Modul / Service | Fokus |
|---|---|---|
graph.service.spec.ts |
GraphService | Microsoft Graph API Client |
utcm.service.spec.ts |
UtcmService | UTCM Snapshot Job und Monitor API |
auth.service.spec.ts |
AuthService | Authentifizierung und JWT Handling |
users.service.spec.ts |
UsersService | Benutzer CRUD Operationen |
snapshots.service.spec.ts |
SnapshotsService | Snapshot Lifecycle Management |
rollback.service.spec.ts |
RollbackService | Rollback-Ausführung und -Historie |
baselines.service.spec.ts |
BaselinesService | Baseline Management und Evaluation |
compliance-engine.spec.ts |
ComplianceEngine | Regel-Evaluation und Scoring |
notifications.service.spec.ts |
NotificationsService | Multi-Channel Benachrichtigungen |
reports.service.spec.ts |
ReportsService | Report-Generierung |
registry.service.spec.ts |
RegistryService | UTCM Resource Registry |
setup.service.spec.ts |
SetupService | System-Initialisierungs-Wizard |
ai-analysis.service.spec.ts |
AIAnalysisService | KI-gestützte Konfigurationsanalyse |
configuration-drift.service.spec.ts |
ConfigurationDriftService | Drift Detection und Monitoring |
risk-assessment.service.spec.ts |
RiskAssessmentService | Risikobewertung und Heat Maps |
change-management.service.spec.ts |
ChangeManagementService | Änderungsanträge und Approvals |
compliance.service.spec.ts |
ComplianceService | Framework Compliance Evaluation |
audit-evidence.service.spec.ts |
AuditEvidenceService | Evidenz-Sammlung |
copilot-readiness.service.spec.ts |
CopilotReadinessService | Copilot Readiness (21 Testfaelle) |
vendor-adapter-registry.spec.ts |
VendorAdapterRegistry | Adapter-Registrierung und Lookup |
m365-adapter.spec.ts |
M365Adapter | M365 VendorAdapter (12 Tests) |
zscaler-adapter.spec.ts |
ZscalerAdapter | Zscaler VendorAdapter (18 Tests) |
zscaler-auth-factory.spec.ts |
ZscalerAuthFactory | ZIA/ZPA Authentifizierung |
zscaler-rate-limiter.spec.ts |
ZscalerRateLimiter | Rate Limiting |
zscaler-zia-client.spec.ts |
ZscalerZiaClient | ZIA API Client |
zscaler-zpa-client.spec.ts |
ZscalerZpaClient | ZPA API Client (10 Tests) |
tenant-access.service.spec.ts |
TenantAccessService | IDOR Prävention |
tenant-schema-manager.spec.ts |
TenantSchemaManager | Schema Lifecycle (23 Tests) |
scheduler.service.spec.ts |
SchedulerService | Geplante Drift Checks |
user.entity.spec.ts |
User Entity | Entity Validation |
password.util.spec.ts |
PasswordUtil | Passwort Hashing und Vergleich |
permissions.util.spec.ts |
PermissionsUtil | Permission-Berechnung |
user-role.enum.spec.ts |
UserRole Enum | Rollen-Hierarchie Validierung |
Cross-Tenant Isolation Tests¶
TCM365 beinhaltet 70+ dedizierte Cross-Tenant Isolation Tests, die sicherstellen, dass keine Daten zwischen Organisationen über die drei Isolationsschichten hinweg durchsickern.
Was wird getestet¶
| Testkategorie | Tests | Validiert |
|---|---|---|
| TenantAccessService | 15+ | IDOR Prävention, Org-Level Zugriffspruefung |
| Snapshots Cross-Tenant | 10+ | Snapshot-Datenisolation zwischen Orgs |
| Workflows Cross-Tenant | 8+ | Workflow-Ausfuehrungsisolation |
| Drift Cross-Tenant | 8+ | Drift-Datensaetze pro Tenant isoliert |
| Rollback Cross-Tenant | 8+ | Rollback-Historie Isolation |
| Baselines Cross-Tenant | 8+ | Baseline-Datenisolation |
| VendorTenant IDOR | 15+ | VendorTenant Zugriffskontrolle (seit v2.1.0) |
Cross-Tenant Test Pattern¶
describe('Cross-Tenant Isolation', () => {
let orgAService: SnapshotsService;
let orgBService: SnapshotsService;
beforeEach(() => {
// Zwei isolierte Tenant-Kontexte aufsetzen
orgAService = createServiceWithTenant('org-a-uuid');
orgBService = createServiceWithTenant('org-b-uuid');
});
it('should not allow Org B to access Org A snapshots', async () => {
// Org A erstellt einen Snapshot
const snapshot = await orgAService.create({ ... });
// Org B versucht darauf zuzugreifen
await expect(
orgBService.findOne(snapshot.id),
).rejects.toThrow('TENANT_ACCESS_DENIED');
});
});
Drei Isolationsschichten
Die Cross-Tenant Tests validieren alle drei Schichten: TenantAccessService (IDOR Prävention im Code), PostgreSQL RLS (Row-Level Security auf DB-Ebene) und Per-Tenant Schemas (tenant_{uuid} Schema-Isolation).
Test Patterns¶
Dependencies Mocken¶
Verwenden Sie jest.fn() und NestJS Test.createTestingModule für Dependency-Isolation:
describe('SnapshotsService', () => {
let service: SnapshotsService;
let mockRepository: jest.Mocked<Repository<Snapshot>>;
let mockVendorRegistry: jest.Mocked<VendorAdapterRegistry>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
SnapshotsService,
{
provide: getRepositoryToken(Snapshot),
useValue: {
find: jest.fn(),
findOne: jest.fn(),
save: jest.fn(),
delete: jest.fn(),
},
},
{
provide: VendorAdapterRegistry,
useValue: {
getAdapter: jest.fn(),
},
},
],
}).compile();
service = module.get<SnapshotsService>(SnapshotsService);
mockRepository = module.get(getRepositoryToken(Snapshot));
mockVendorRegistry = module.get(VendorAdapterRegistry);
});
it('should create a snapshot', async () => {
const mockAdapter = {
captureConfiguration: jest.fn().mockResolvedValue([
{ resourceType: 'microsoft.entra.users', data: {}, itemCount: 10, capturedAt: new Date() },
]),
};
mockVendorRegistry.getAdapter.mockReturnValue(mockAdapter as any);
mockRepository.save.mockResolvedValue({ id: 'uuid', status: 'completed' } as any);
const result = await service.create({ vendorTenantId: 'tenant-uuid' });
expect(result.status).toBe('completed');
expect(mockAdapter.captureConfiguration).toHaveBeenCalled();
});
});
Guards und Decorators testen¶
describe('RolesGuard', () => {
it('should allow SUPER_ADMIN to access TENANT_ADMIN endpoint', () => {
const guard = new RolesGuard(reflector);
const context = createMockContext({ user: { role: UserRole.SUPER_ADMIN } });
expect(guard.canActivate(context)).toBe(true);
});
it('should deny VIEWER from accessing TENANT_ADMIN endpoint', () => {
const guard = new RolesGuard(reflector);
const context = createMockContext({ user: { role: UserRole.VIEWER } });
expect(guard.canActivate(context)).toBe(false);
});
});
Asynchrone Operationen testen¶
it('should handle async zlib compression', async () => {
const data = Buffer.from(JSON.stringify({ test: true }));
const compressed = await gzipAsync(data);
const decompressed = await gunzipAsync(compressed);
expect(JSON.parse(decompressed.toString())).toEqual({ test: true });
});
Frontend E2E Testing¶
Framework¶
TCM365 verwendet Playwright für End-to-End Tests.
E2E Tests ausführen¶
cd frontend
# Alle E2E Tests ausführen
npm run test:e2e
# Nur API E2E Tests (Browser-Tests ueberspringen)
SKIP_SERVER=1 npm run test:e2e:api
Test-Struktur¶
E2E Tests befinden sich in frontend/e2e/ oder frontend/tests/e2e/ und folgen dem Playwright Test Pattern:
import { test, expect } from '@playwright/test';
test('user can log in and view dashboard', async ({ page }) => {
await page.goto('/');
await page.fill('[data-testid="email"]', 'admin@tcm.local');
await page.fill('[data-testid="password"]', 'Admin123!TCM');
await page.click('[data-testid="login-button"]');
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('h1')).toContainText('Dashboard');
});
Coverage Tracking¶
Coverage Report generieren:
Der Coverage Report wird in backend-js/coverage/ generiert und beinhaltet:
- Line Coverage
- Branch Coverage
- Function Coverage
- Statement Coverage
Coverage-Ziele
Obwohl kein erzwungener Coverage-Schwellwert existiert, zielt das Projekt auf hohe Coverage bei kritischen Pfaden: Authentifizierung, Tenant-Isolation, Snapshot Management, Drift Detection und Rollback-Operationen.
Neue Tests schreiben¶
Checkliste für neue Features¶
Beim Hinzufügen eines neuen Features sicherstellen, dass folgende Tests existieren:
- Unit Tests für Service-Methoden
- DTO Validierungs-Tests (optional, durch class-validator abgedeckt)
- Guard/Permission Tests für geschuetzte Endpoints
- Cross-Tenant Isolation Tests falls das Feature tenant-bezogen ist
- Fehlerbehandlungs-Tests für Edge Cases und Fehlerfaelle
- Integrationstests für komplexe Workflows (optional)
Test-Namenskonvention¶
Verwenden Sie beschreibende it Bloecke, die als Spezifikationen lesbar sind:
describe('BaselinesService', () => {
describe('evaluate()', () => {
it('should return 100% compliance when all rules pass', async () => { ... });
it('should calculate weighted score based on rule severity', async () => { ... });
it('should mark rules as not-applicable when resource type missing', async () => { ... });
it('should throw if baseline does not exist', async () => { ... });
});
});
CI/CD Integration¶
Tests laufen automatisch in der Azure Pipelines CI/CD Pipeline:
npm ci-- Dependencies installierennpm run lint-- Code Quality Checknpm test-- Unit und Integration Testsnpm run build-- Build Verifikation
Pipeline-Blockade
Fehlschlagende Tests blockieren die Pipeline und verhindern das Deployment. Stellen Sie sicher, dass alle Tests lokal bestehen, bevor Sie Änderungen pushen.