Skip to content

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:

cd backend-js
npm run test:cov

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:

  1. npm ci -- Dependencies installieren
  2. npm run lint -- Code Quality Check
  3. npm test -- Unit und Integration Tests
  4. npm 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.