Die beiden gleichen Kopien entfallen; common v0.2.2. Das Testpflicht-Muster fuer bearerauth wandert vom workflow-Gate in das common-Gate. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
12 KiB
NEXARCH Workflow – Teststrategie
Stand: 2026-10-16. Ticket: QA-01. Vorbild: Core QA-01 (docs/TESTSTRATEGIE-CORE.md,
Fertig), dieselbe Struktur wie Mail (mail/docs/TESTSTRATEGIE-MAIL.md) und AI
(ai/docs/TESTSTRATEGIE-AI.md) — fuer Workflow uebernommen und um die vier
Teilbereiche ergaenzt, die dieses Modul tatsaechlich hat: Engine, Genehmigungen,
Aufgaben, Routing.
1. Warum dieses Dokument existiert
archivdms (Vorgaengerprojekt) hatte 0 Tests fuer auth/storage/permissions.go
bei insgesamt nur 2 _test.go-Dateien in ganz internal/; archivmail testete 2 von
18 Modulen. NEXARCH Core legte deshalb in QA-01 fest: Testpflicht fuer Auth,
Tenant-Scoping und Zugriffspruefung ist ein Merge-Gate, keine Nachruestung.
Workflow uebernimmt denselben Grundsatz — hier zusaetzlich konkret gemacht fuer die
sicherheitsrelevanten Stellen, die Workflow tatsaechlich hat (Abschnitt 4), statt
den Grundsatz nur zu wiederholen.
Workflow ist zum Zeitpunkt dieses Tickets kein Neubau mehr wie Mail bei dessen
QA-01: Engine (ENG-01/ENG-03/ENG-04), Genehmigungen (APR-01 bis APR-04), Aufgaben
(TSK-01/TSK-02) und Routing (RTE-01 bis RTE-05) existieren bereits mit eigenen
_test.go-Dateien je Ticket. Dieses Dokument macht explizit, was bisher implizit je
Ticket entschieden wurde, und schliesst die eine echte Luecke, die eine Durchsicht
ergeben hat (Abschnitt 4, 7).
2. Testpyramide
| Ebene | Werkzeug | Umfang |
|---|---|---|
| Unit | go test (Standardbibliothek) |
Einzelne Funktionen/Typen ohne externe Abhaengigkeit, z. B. processdef.Parse-Validierung, routingrule.Rule.Matches, delegation-Zeitraumlogik |
| Integration | go test gegen echte PostgreSQL-Instanz (testdb.Pool, eigenes Schema je Testlauf) |
Repository-/Service-Schicht: statemachine.Engine, approval.Service, dualcheck.Service, task.Store, routingrule.Store — alle bestehenden *_test.go in internal/* folgen bereits diesem Muster |
| Vertragstest (Modulgrenze) | go test gegen moduleadapter-HTTP-Schnittstelle (ENG-02), echter httptest.Server-Roundtrip |
DMS/Mail rufen Workflow ausschliesslich ueber internal/moduleadapter auf; moduleadapter_test.go/handler_test.go sind die bestehende Grundlage. Ein modulübergreifender Vertragstest mit echten DMS-/Mail-Konsumenten (analog archive-contract-tests.yml/contract-tests.yml) ist noch nicht eingerichtet, siehe Abschnitt 7 |
| E2E | Echter HTTP-Roundtrip ueber cmd/workflow-app (main_test.go startet den echten Mux) bis zum ersten Workflow-Frontend-Ticket, danach Playwright/Jest gegen die echten UIs (web/task-board, web/workflow-approvals, web/routing-rules, web/workflow-cases) |
Vollstaendiger Request-Response-Zyklus, kein reiner Funktionsaufruf |
E2E-Zwischenloesung begruendet: Dieselbe Begruendung wie bei Mail — ein echter
HTTP-Roundtrip ueber den tatsaechlich gestarteten Dienst (cmd/workflow-app, kein
reiner In-Process-Aufruf) ist die ehrliche Untergrenze, bis die UI-Tickets fertig
sind und Playwright/Jest eine echte Oberflaeche zum Testen haben.
3. Beispieltests je Testart und Bereich (Akzeptanzkriterium 1)
Kein Wegwerf-Demo — Verweis auf real existierende, bereits gruene Tests je Bereich:
| Bereich | Unit | Integration | Vertrag/E2E |
|---|---|---|---|
| Engine | internal/processdef/processdef_test.go (Schema-Validierung) |
internal/statemachine/statemachine_test.go, history_test.go (Zustandsautomat, Historie, optimistische Sperre) |
cmd/workflow-app/main_test.go |
| Genehmigungen | internal/dualcheck/dualcheck_test.go (Regel-Logik ohne DB-Seiteneffekt, soweit isolierbar) |
internal/approval/approval_test.go, approval_delegation_test.go, internal/delegation/delegation_test.go |
internal/approvalapi/handler_test.go |
| Aufgaben | — (Validierung in task.go wird integriert mitgetestet) |
internal/task/task_test.go |
internal/caseoverviewapi/caseoverviewapi_test.go (Aufgaben-Bezug in der Fallübersicht) |
| Routing | internal/routingrule/routingrule_test.go (Matches-Bedingungsauswertung) |
internal/routingengine/routingengine_test.go, internal/routingsim/routingsim_test.go |
internal/routingruleapi/handler_test.go |
Zusaetzlich fuer QA-01 real durchgefuehrt: internal/fixtureset/fixtureset_test.go
saet den unter Abschnitt 5 beschriebenen Testdatenbestand ueber die echten
Domaenen-Services in eine frische Testdatenbank und prueft das Ergebnis (siehe
Abschnitt 6, Pruefung 2) — ein weiteres Integrationstest-Beispiel, das alle vier
Bereiche in einem Lauf abdeckt.
4. Pflichttests als Merge-Gate fuer sicherheitsrelevanten Code (Akzeptanzkriterium 4)
Verbindlich fuer jeden Pull Request, der Dateien in einem der folgenden Pakete
aendert — jede geaenderte .go-Datei muss von einer geaenderten oder neuen
_test.go-Datei im selben Package begleitet sein, identisch zur Regel aus Core
QA-01:
- Auth-nahe Logik:
workflow/internal/svcauth/(Service-Token-Vergleich in konstanter Zeit),workflow/internal/moduleadapter/(prueftX-Service-Tokengegensvcauth.Equal— der tatsaechliche Durchsetzungspunkt),common/bearerauth/(prueft das Bearer-Token der Frontends gegen die Core-JWKS;X-User-Idnur noch ueber den Uebergangsschalter; Gate im common-Modul) - Tenant-Scoping:
workflow/internal/tenantregistryclient/(fragt Core TEN-01, muss bei Fehler fail-closed bleiben),workflow/internal/backchannel/undworkflow/internal/backchannelapi/(extern erreichbarer Eingang, der den Tenant-Slug vor jeder Aktion gegen die Registry verifiziert, VOR-06) - Zugriffspruefung (Vier-Augen/Vertretung):
workflow/internal/dualcheck/(APR-02,ErrSameAsCreatorverhindert Selbstbestaetigung),workflow/internal/delegation/(APR-04,ErrSelfSubstitutionverhindert Selbst-Vertretung als Umgehung des Vier-Augen-Prinzips)
Diese sieben Pakete wurden bewusst ausgewaehlt, nicht ganz Engine/Genehmigungen/
Aufgaben/Routing: Business-Logik wie task.go oder routingengine.go ist bereits
heute durchgaengig getestet (Abschnitt 3), aber kein Tenant-/Auth-Gate im engeren
Sinn. Diese sieben Stellen sind es, weil sie entweder eine Identitaet pruefen
(svcauth, moduleadapter, tenantregistryclient) oder eine Umgehung eines
Zugriffskontrollmechanismus verhindern (dualcheck, delegation, backchannel/-api).
internal/pflichttestgate implementiert das Gate (Code-Kopie des Musters aus Core
internal/pflichttestgate bzw. Mail mail/internal/pflichttestgate — Workflow ist
ein eigenstaendiges Go-Modul und kann die anderen nicht importieren).
.gitea/workflows/workflow-pflichttest-gate.yml fuehrt es gegen jeden PR-Diff aus,
der Dateien unter workflow/** aendert.
Negativtest des Gates selbst (Pruefung 1 dieses Tickets):
internal/pflichttestgate/gate_test.go simuliert Diffs mit geaenderten Dateien in
allen sieben Paketen ohne begleitende Testdatei und erwartet je einen Verstoss;
ein zusaetzlicher Fall prueft, dass eine begleitende _test.go-Datei das Gate
bestehen laesst und ein nicht-sensibler Pfad ignoriert wird.
5. Testdatenbestand (Akzeptanzkriterium 2)
testdata/fixtures/*.json haelt einen realistischen, vollstaendig synthetischen
Datenbestand fuer alle vier Bereiche, angelehnt an das tatsaechliche Szenario, fuer
das Workflow gebaut wird (Kanzlei-Akte/Posteingang ueber DMS/Mail):
engine.json— zwei Prozessdefinitionen (dokumentfreigabe,fristsache) im ENG-03-Format plusseed_instances, die je Definition eine echte Instanz starten und mindestens einen Uebergang ausfuehren (realeworkflow_instances-/workflow_instance_history-Zeilen, keine reinen Definitionsstubs)approvals.json— drei Genehmigungsaufgaben, zwei aktivierte Vier-Augen- Prozesstypen (dualcheck_process_types) und eine Vertretungsregel (delegation_rules)tasks.json— drei Aufgaben (Person- und Gruppenzuweisung, alle drei Prioritaetsstufen, mit Modul-Referenzen auf DMS/Mail-Objekte)routing.json— drei Routing-Regeln mit unterschiedlicher Prioritaet und allen drei Bedingungsoperatoren (equals,in) sowie beiden Aktionstypen
Anonymisierung: Personen/Gruppen sind durchgaengig Slugs
(anwalt.weber, ra-fachangestellte.kowalski, team-scanstelle) statt
Klarnamen oder E-Mail-Adressen; Aktenzeichen (AZ-2026-0142) und
Posteingangs-IDs sind frei erfunden und folgen keinem echten Nummernkreis.
internal/fixtureset/fixtureset_test.go (TestFixtures_ContainNoEmailLikePII)
prueft automatisiert, dass keine der Fixture-Dateien ein @-Zeichen enthaelt —
eine harte, maschinell pruefbare Untergrenze gegen versehentlich eingestreute
E-Mail-Adressen oder aehnliche Kontaktdaten.
internal/fixtureset laedt die JSON-Dateien und saet sie ueber die echten
Domaenen-Services (processdef.Registry, approval.Service, dualcheck.Rules,
delegation.Store, task.Store, routingrule.Store) statt per Roh-SQL — die
Fixtures durchlaufen damit dieselben Validierungen wie Produktionsdaten
(z. B. ErrInvalidAssigneeType, Schema-Pruefung von processdef.Parse).
6. Verantwortlichkeit je Testebene (Akzeptanzkriterium 3)
| Testebene | Verantwortlich | Wann |
|---|---|---|
| Unit | Entwickler:in des Tickets | Lokal vor jedem Commit |
Integration (testdb/TEST_TENANT_DSN) |
Entwickler:in des Tickets | Lokal vor jedem Commit; in CI bei jedem Push/PR (ci.yml-Aequivalent fuer Workflow, sobald eingerichtet — siehe Abschnitt 7) |
| Pflichttest-Gate (Abschnitt 4) | CI (workflow-pflichttest-gate.yml), durchgesetzt unabhaengig vom Willen der Entwickler:in |
Automatisch bei jedem PR auf workflow/** — blockierend, kein Review-Ermessen |
Vertragstest (moduleadapter) |
Modul-Owner Workflow gemeinsam mit DMS-/Mail-Owner | Bei jeder Aenderung an der ENG-02-Schnittstelle |
| E2E / UI | QA (zweite Person) nach jedem UI-Ticket, danach als Teil der Review-Checkliste | Vor Abnahme eines UI-Tickets |
| Teststrategie-Dokument selbst | Zweite Person (Gegenlesen), siehe Abschnitt 7 | Einmalig vor Abnahme dieses Tickets, danach bei strukturellen Aenderungen |
7. Pruefungen (real durchgefuehrt)
| # | Pruefung | Ergebnis |
|---|---|---|
| 1 | Negativtest des Gates: Diff mit sicherheitsrelevanter Aenderung ohne Test schlaegt kontrolliert fehl | bestanden — go test ./internal/pflichttestgate/... -v auf 204, alle vier Faelle (fehlender Test je der sieben Pakete, begleiteter Test, nicht-sensibler Pfad, alle sieben Pakete gleichzeitig) grün |
| 2 | Testdatenbestand enthaelt keine echten Personendaten | bestanden — TestFixtures_ContainNoEmailLikePII automatisiert (kein @ in den Fixture-Dateien) plus manuelle Durchsicht aller vier JSON-Dateien: ausschliesslich Slugs, erfundene Aktenzeichen, keine realen Namen/Domains |
| 3 | Zweite Person kann Teststrategie ohne Rueckfragen anwenden | offen — siehe Abschnitt 8; in dieser Session keine zweite Person verfuegbar |
Zusaetzlich real ausgefuehrt (Grundlage fuer Abschnitt 3/5): go build ./...,
go vet ./... und go test ./... -p 1 -count=1 fuer das gesamte Workflow-Modul auf
Host 204 gegen dms_dev-Testinfrastruktur, inklusive
internal/fixtureset/fixtureset_test.go (saet alle vier Fixtures real in eine
frische Testdatenbank und prueft zusaetzlich, dass die Vier-Augen-Regel eine
Selbstbestaetigung ablehnt und die Vertretungsregel korrekt auflöst).
8. Offene Punkte
- Pruefung 3 (zweite Person liest gegen) ist noch nicht durchgefuehrt — erfordert eine echte zweite Person, nicht durch eine weitere Session ersetzbar.
- Ein modulübergreifender Vertragstest mit echten DMS-/Mail-Konsumenten der
moduleadapter-Schnittstelle (analogarchive-contract-tests.yml/contract-tests.yml) ist noch nicht eingerichtet; aktuell decktmoduleadapter_test.godie Schnittstelle nur aus Workflow-Sicht ab. - Es gibt noch kein eigenes
workflow-ci.ymlfuer Build/Vet/Test/Coverage des gesamten Moduls bei jedem Push (wieci.ymles fuer Core/DMS/Connect tut) — nur das in diesem Ticket ergaenzte Pflichttest-Gate. Ausserhalb des Umfangs dieses Tickets (QA-01 ist Teststrategie + Merge-Gate fuer sicherheitsrelevanten Code, nicht allgemeines CI-Setup), aber als Folgeticket sinnvoll.