Compare commits

..

No commits in common. "57028fba23aa373c0cb8a78390dc414ae366a622" and "e5ba31425c203a35cfca35d6492747b4867d5650" have entirely different histories.

16 changed files with 193 additions and 1680 deletions

View File

@ -1,228 +0,0 @@
# Fahrplan Modul Kundenverwaltung (Gruppe H) Ver. 1.2
**Projekt:** Fakturierungssystem · SE1 Team 2 Hochschule Mannheim
**Modul / Gruppe:** Kundenverwaltung (Gruppe H) · Package `de.hsmannheim.faktura.kunde`
**Verantwortlich (dieses Dokument):** Christopher Lampert [3027248]
**Gruppe H:** Oleg Akimenko [3028868] (Gruppenleiter), Christopher Lampert [3027248], Kenan Pekarovic [3027541]
**Stand:** 26.06.2026
**Bezug:** Lastenheft v1.1, Pflichtenheft v1.0, Project Charter v1.1, Modultestplan (KV-Teil), Modultestbericht KV v1.0
> **Harte Deadline:** Montag, **29.06.2026, 09:00 Uhr** Abgabe der Artefakte pro Team.
> **Präsentation:** Montag, 29.06.2026 im regulären Vorlesungsblock (2025 Min/Team, 4 Vortragende, je Gruppe ein Vertreter).
> **Projektphase laut Charter:** M7 „Puffer & Abnahme" (27.30.06.2026).
*Änderung gegenüber v1.1: Phase 6 (Modultests MT-KV-01…11) und Phase 7 (Modultestbericht, P7-1/P7-2) abgeschlossen; Statusmarker, „Aktuelle Position" und Umsetzungsstand aktualisiert; offener Punkt OP-4 (K1 ohne „alle Kunden"-Methode) ergänzt; fehlerhafte Export-Marker entfernt.*
---
## 0. So benutzt du diesen Fahrplan
Jeder Schritt hat einen Status. Aktualisiere ihn, dann kannst du mir jederzeit sagen „ich bin bei P8-1" und ich habe sofort den Kontext.
**Statuslegende:**
`[ ]` offen · `[~]` in Arbeit · `[x]` fertig · `[!]` blockiert / offener Punkt
**Aktuelle Position:** *Phasen 07 (KV-Kern + Modultestbericht) abgeschlossen nächster Schritt: Phase 8 (Integration) bzw. Team-Abstimmung P7-3.*
### 🚀 Aktueller Umsetzungsstand (für den neuen Chat-Kontext)
Die **Phasen 0 bis 7** der Kundenverwaltung sind umgesetzt: Datenmodell, Persistenz, Validierung, Service-Logik und DP-Schnittstelle stehen, die **11 Modultests MT-KV-01…11** sind grün, und der **Modultestbericht** ist erstellt. Alle entwickelten Klassen sind funktionsfähig und durch JUnit-5-Tests abgedeckt; die Logikschicht erreicht **85 % Line Coverage** (NF-TEST-03 ≥ 60 % erfüllt).
#### 📁 Erstellte Dateien & Paketstruktur (`de.hsmannheim.faktura.kunde`)
* **Wurzelverzeichnis:** `pom.xml` (Maven-Setup für Java 17, JUnit 5 und Jackson) sowie `.gitignore` (ignoriert `target/` und `.idea/`).
* **`model`:** `Kunde.java` (spezifikationskonformes POJO mit allen 12 Feldern, PLZ als `String`).
* **`repository`:**
* `KundeRepository.java` (Interface für Datenhaltung).
* `KundeContainer.java` (Hilfsklasse für JSON-Bündelung inkl. ID-Zähler).
* `KundeRepositoryJson.java` (Jackson-Implementierung mit fortlaufendem ID-Zähler gegen ID-Wiederverwendung).
* **`service`:**
* `KundeService.java` (zentrale CRUD-Logik inkl. `finde(long)` für die Beleg-Schnittstelle K3).
* `KundeValidator.java` (Pflichtfelder, E-Mail-Format, Bedingung `firmenname || nachname`).
* `BelegReferenzPruefer.java` (funktionales Interface zur Entkopplung der GR-05-Löschsperre von Gruppe F).
* `ValidierungsException.java` & `LoeschsperreException.java` (Unchecked Exceptions).
* **`src/test/java`:**
* `KundeModultestTest.java` konsolidierte Modultestdatei mit **genau 11 Tests** (MT-KV-01…11, 1:1 zum Modultestplan, je `@DisplayName`). Ersetzt die früheren Einzeldateien `KundeServiceTest`, `KundeValidatorTest` und `KundeRepositoryJsonTest` (deren Abdeckung vollständig übernommen wurde; vgl. P10-2 „max. 4 Test-Dateien").
* **Abgabe-Artefakt:** `Modultestbericht_Kundenverwaltung_v1_0` (Testergebnisse, Coverage-Nachweis, Abdeckungsübersicht).
---
## 1. Ziel & Abgrenzung
**Im Scope (nur Gruppe H):** Anlegen, Bearbeiten, Suchen und Löschen von Kunden samt Validierung, Persistenz und Modultests also die fachlichen Anforderungen **F-KV-01 bis F-KV-04** (Herkunft BA-KV-01…04) sowie die mitwirkenden Regeln **GR-05** (Stammdatenschutz) und **NF-ARCH-01** (Persistenz).
**Nicht im Scope (andere Gruppen):** Produktverwaltung (G), Dokumentenprozess (F), GUI (E). Diese werden hier **nur über die Schnittstellen** berührt (siehe Abschnitt 2).
**Leitprinzip:** Alles richtet sich nach den vier Projektdokumenten. Abweichungen werden **nicht still aufgelöst**, sondern als offener Punkt in Abschnitt 8 markiert.
---
## 2. Kompatibilitätsvertrag mit den anderen Modulen
Damit die Kundenverwaltung sauber mit den Teilen der anderen Teilnehmer zusammenspielt, müssen diese vier Berührungspunkte exakt eingehalten werden. **Bevor integriert wird, sollten diese Signaturen mit Gruppe E und F gegengeprüft sein.**
| # | Wer braucht es | Was die Kundenverwaltung liefern muss | Quelle |
|---|----------------|----------------------------------------|--------|
| K1 | **GUI (Gruppe E)** über IF-01 | `KundeService` mit `anlegen(Kunde): long`, `bearbeiten(Kunde): void`, `suchen(String): List<Kunde>`, `loeschen(long): void` | Pflichtenheft Klassendiagramm (Kap. 7.2), Komponentendiagramm (Kap. 7.1: `KundeAnsicht → KundeService`) |
| K2 | **Datenhaltung** über IF-02 | `KundeRepository`-Interface (speichern/findeById/findeAlle/loeschen), JSON-Persistenz dahinter gekapselt | IF-02, NF-ARCH-01/02 |
| K3 | **Dokumentenprozess (Gruppe F)** | Kunde ist über `kundeId` (long) referenzierbar; F nutzt `FakeCustomerLookup` und `isCustomerReferenced(...)` in seinen Tests (MT-DP-16). KV muss einen Kunden per ID auflösbar machen (`finde(long): Optional<Kunde>`). | Modultestplan DP (MT-DP-01, MT-DP-16); Pflichtenheft Datenobjekte (kundeId als Referenz in allen Belegen) |
| K4 | **Löschsperre GR-05** | Vor dem Löschen prüft `KundeService`, ob der Kunde in einem Beleg referenziert ist → Abfrage gegen `BelegRepository` (Gruppe F). Bei Referenz: Löschen ablehnen. | GR-05; F-KV-04; MT-KV-11 |
**Daten-Kontrakt „Kunde" (Pflichtenheft Kap. 6.1.2) verbindlich:**
| Attribut | Java-Typ | Pflicht | Constraint |
|----------|----------|---------|------------|
| kundeId | `long` | Pflicht | Fortlaufender, eindeutiger Primärschlüssel |
| firmenname | `String` | Pflicht\* | Pflicht, sofern kein Nachname |
| nachname | `String` | Pflicht\* | Pflicht, sofern kein Firmenname |
| vorname | `String` | Optional | |
| strasse | `String` | Pflicht | Straße + Hausnummer |
| plz | `String` | Pflicht | String (führende Nullen erhalten) |
| ort | `String` | Pflicht | |
| telefon | `String` | Optional | |
| email | `String` | Optional | Formatvalidierung, falls angegeben |
| ustIdNr | `String` | Optional | USt-IdNr. |
| lieferadresse | `String` | Optional | abweichende Lieferadresse |
| ansprechpartner | `String` | Optional | |
\* **Constraint:** `firmenname != null || nachname != null` (mindestens eines befüllt).
---
## 3. Technische Vorgaben (aus Pflichtenheft Kap. 2.3)
- **Sprache:** Java LTS ≥ 17
- **Persistenz:** lokale **JSON-Datei** (z. B. Jackson), hinter `KundeRepository` gekapselt → austauschbar (NF-ARCH-02)
- **Tests:** **JUnit 5 (Jupiter)** GUI-unabhängige Logiktests (NF-TEST-02)
- **Architektur:** 3-Schichten (ui → service → repository); KV berührt nur `service` + `repository`
- **Versionierung:** Git / Gitty, Code-Review je Merge (NF-VER-02)
- **Relevante NF-Ziele:** NF-USE-01 (Kunde anlegen < 2 min), NF-PERF-01 (Aktion < 1 s bei 1.000 Kunden), NF-PERF-02 (Liste < 2 s), NF-SEC-01 (kein Klartext von außen), NF-SEC-02 (DSGVO-Löschen)
---
## 4. Die Phasen (Schritt für Schritt)
### Phase 0 Setup & Abstimmung
- `[x]` **P0-1** Git/Gitty: Branch für Gruppe H angelegt und Paketstruktur erstellt.
- `[x]` **P0-2** Build-Setup: Maven mit Java 17, JUnit 5 und Jackson in `pom.xml` aufgesetzt.
- `[ ]` **P0-3** Schnittstellen K1K4 mit Gruppe E und F gegenprüfen *(wird bei Integration relevant, Phase 8)*.
- `[ ]` **P0-4** Offenen Punkt OP-1 mit Team klären *(Code ist durch Interface entkoppelt)*.
### Phase 1 Datenmodell
- `[x]` **P1-1** Klasse `Kunde` mit allen 12 Attributen erstellt (`plz` als `String`).
- `[x]` **P1-2** Getter/Setter und `equals`/`hashCode` über `kundeId` implementiert.
- `[x]` **P1-3** JSON-Serialisierbarkeit via Jackson durch leeren Konstruktor sichergestellt.
### Phase 2 Persistenz (IF-02 / NF-ARCH-01/02)
- `[x]` **P2-1** Interface `KundeRepository` mit CRUD-Signaturen definiert.
- `[x]` **P2-2** `KundeRepositoryJson` lädt/speichert lokale JSON-Datei via Jackson.
- `[x]` **P2-3** Fortlaufende ID-Vergabe über mitgespeicherten Zähler gelöst (kein ID-Reuse nach Löschung).
- `[x]` **P2-4** Persistenz-Roundtrip geprüft (jetzt in MT-KV-06 enthalten).
### Phase 3 Validierung
- `[x]` **P3-1** Pflichtfeldprüfung für `strasse`, `plz`, `ort` in `KundeValidator` eingebaut.
- `[x]` **P3-2** Constraint `firmenname != null || nachname != null` umgesetzt.
- `[x]` **P3-3** E-Mail-Formatprüfung per Regex integriert.
- `[x]` **P3-4** `ValidierungsException` erstellt; wird vor dem Speichern geworfen, um ungültige Daten zu blockieren.
### Phase 4 Logik: `KundeService` (F-KV-01…04)
- `[x]` **P4-1** `anlegen(Kunde)` validiert, erzwingt ID-Vergabe und persistiert. · **F-KV-01 / BA-KV-01**
- `[x]` **P4-2** `bearbeiten(Kunde)` prüft Existenz, validiert und speichert. · **F-KV-02 / BA-KV-02**
- `[x]` **P4-3** `suchen(String)` filtert über Name (case-insensitive) und Kundennummer. · **F-KV-03 / BA-KV-03**
- `[x]` **P4-4** `loeschen(long)` prüft Existenz und wirft bei aktiver Referenz eine `LoeschsperreException`. · **F-KV-04 / BA-KV-04**
- `[x]` **P4-5** GR-05-Löschsperre über das Interface `BelegReferenzPruefer` vollständig vorbereitet und isoliert getestet.
### Phase 5 Schnittstelle zum Dokumentenprozess (K3)
- `[x]` **P5-1** `KundeService.finde(long): Optional<Kunde>` als Schnittstelle für Gruppe F bereitgestellt.
- `[ ]` **P5-2** Mit Gruppe F genaue Aufrufrichtung für `isCustomerReferenced` abstimmen *(offen, Integration)*.
### Phase 6 Modultests (JUnit 5, MT-KV-01…11) ✅ abgeschlossen
*Die fachliche Logik wurde in genau die 11 im Modultestplan geforderten Testmethoden überführt konsolidiert in `KundeModultestTest`, jeweils mit `@DisplayName` (MT-KV-ID sichtbar im Testlauf):*
- `[x]` **P6-01** MT-KV-01 Kunde mit allen Pflichtattributen anlegen → gespeichert · BA-KV-01
- `[x]` **P6-02** MT-KV-02 ohne Firmenname/Nachname → abgelehnt · BA-KV-01
- `[x]` **P6-03** MT-KV-03 ohne Straße → abgelehnt · BA-KV-01
- `[x]` **P6-04** MT-KV-04 ungültige E-Mail „kunde@" → abgelehnt · BA-KV-01
- `[x]` **P6-05** MT-KV-05 Telefonnummer ändern → gespeichert · BA-KV-02
- `[x]` **P6-06** MT-KV-06 Persistenz nach Neuladen → unverändert · BA-KV-02, NF-ARCH-01
- `[x]` **P6-07** MT-KV-07 Suche über Namen „Muster" → gefunden · BA-KV-03
- `[x]` **P6-08** MT-KV-08 Suche über Kundennummer → gefunden · BA-KV-03
- `[x]` **P6-09** MT-KV-09 Suche ohne Treffer → leeres Ergebnis · BA-KV-03
- `[x]` **P6-10** MT-KV-10 nicht referenzierten Kunden löschen → entfernt · BA-KV-04
- `[x]` **P6-11** MT-KV-11 referenzierten Kunden löschen → abgewiesen · BA-KV-04, GR-05
- `[x]` **P6-12** Alle 11 Tests grün; Coverage nachgewiesen: **85 % Line Coverage** im Paket `…kunde.service` (NF-TEST-03 ≥ 60 % erfüllt).
### Phase 7 Abgabe-Artefakt: Modultestbericht ✅ weitgehend abgeschlossen
- `[x]` **P7-1** Testlauf dokumentiert: je MT-KV-Fall Ergebnis (bestanden), Datum (26.06.2026), Tester.
- `[x]` **P7-2** Abdeckungsübersicht aus dem Modultestplan (BA-KV-01→MT-KV-01…04 usw.) als Nachweis übernommen.
- `[ ]` **P7-3** Mit Team klären: **max. 4 Dateien** insgesamt → KV-Bericht eigene Datei **oder** in gemeinsame Test-Datei integriert (Koordination mit G/F/E; siehe OP-2).
### Phase 8 Integration mit anderen Modulen
- `[ ]` **P8-1** GUI (E): `KundeAnsicht` ruft `KundeService` Smoke-Test Anlegen/Suchen/Löschen aus der Oberfläche.
- `[ ]` **P8-2** Belege (F): echter Kunde im Angebot referenzierbar; GR-05-Löschsperre greift im integrierten System (MT-DP-16 ↔ MT-KV-11).
- `[ ]` **P8-3** Gesamtsystem startet, KV-CRUD lauffähig (AK-02 Charter).
### Phase 9 Präsentation (KV-Anteil)
Pflichtinhalte laut Aufgabenstellung als KV-Vertreter (1 Person je Gruppe) vorbereiten:
- `[ ]` **P9-1** Demo-Anteil: Kunde anlegen → suchen → bearbeiten → Löschsperre zeigen (referenzierter Kunde).
- `[ ]` **P9-2** **KI-Einsatz:** wo eingesetzt, wie gut hat es funktioniert (konkrete KV-Beispiele).
- `[ ]` **P9-3** **Was nächstes Mal anders:** ehrliche Lessons learned aus der KV-Umsetzung.
- `[ ]` **P9-4** **Modultestplan-Ergebnisse** der KV präsentieren (Abdeckung + Pass-Quote 100 %).
- `[ ]` **P9-5** **Traceability-Stichprobe vorbereiten:** Kette **BA-KV-0x → F-KV-0x → MT-KV-xx → AT-KV-xx** auswendig/griffbereit (Prof prüft stichprobenartig).
### Phase 10 Abgabe & Generalprobe
- `[ ]` **P10-1** Code gemergt, Reviews abgeschlossen (NF-VER-02), Tests grün im Hauptbranch.
- `[ ]` **P10-2** Testbericht + Folien im Team konsolidiert (max. 4 Test-Dateien, genau 1 Foliendatei).
- `[ ]` **P10-3** **Abgabe bis Mo 29.06. 09:00 Uhr.**
- `[ ]` **P10-4** Generalprobe Vortrag + Zeitmessung (2025 Min Team-Budget).
---
## 5. Traceability-Matrix Kundenverwaltung (für die Stichprobenprüfung)
| Anforderung (LH) | Pflichtenheft | Modultests | Akzeptanztest (LH) |
|------------------|---------------|------------|--------------------|
| BA-KV-01 Kunde anlegen | F-KV-01 | MT-KV-01 … MT-KV-04 | AT-KV-01, AT-KV-02 |
| BA-KV-02 Kunde bearbeiten | F-KV-02 | MT-KV-05, MT-KV-06 | AT-KV-03, AT-KV-04 |
| BA-KV-03 Kunde suchen | F-KV-03 | MT-KV-07 … MT-KV-09 | AT-KV-05, AT-KV-06 |
| BA-KV-04 Kunde löschen | F-KV-04 | MT-KV-10, MT-KV-11 | AT-KV-07, AT-KV-08 |
| GR-05 Stammdatenschutz | F-KV-04 (i.V.m. GR-05) | MT-KV-11 | |
| NF-ARCH-01 Persistenz | NF-ARCH-01 | MT-KV-06 | AT-NF-… |
---
## 6. Zeitplan bis Montag
| Tag | Fokus | Status |
|-----|-------|--------|
| **Do 25.06** | Phase 0 + Phase 1 (Setup, Schnittstellen, Datenmodell) | erledigt |
| **Fr 26.06** | Phase 27 (Persistenz, Validierung, Service-Logik, DP-Schnittstelle, 11 Modultests grün, Modultestbericht) | erledigt **KV ist dem Zeitplan voraus** |
| **Sa 27.06** | Puffer + Vorbereitung Integration (Phase 8) und Folien (Phase 9) | offen |
| **So 28.06** | Phase 8 + Phase 9 (Integration, Folien, Traceability-Stichprobe) | offen |
| **Mo 29.06 vor 09:00** | Phase 10 (Konsolidierung, Abgabe, Generalprobe) | offen |
---
## 7. Definition of Done (Kundenverwaltung)
- `[x]` F-KV-01 bis F-KV-04 implementiert und über `KundeService` aufrufbar (K1).
- `[x]` Persistenz über `KundeRepository`/JSON, Daten überleben Neustart (NF-ARCH-01).
- `[x]` Validierung greift (Pflichtfelder, firmenname||nachname, E-Mail-Format).
- `[~]` GR-05-Löschsperre: isoliert getestet (MT-KV-11); im **integrierten** System noch nachzuweisen (Phase 8).
- `[x]` MT-KV-01…11 alle grün, Coverage ≥ 60 % im `kunde`-Paket (85 % Line in `…service`).
- `[~]` Modultestbericht erstellt; Integration ins Team-Sammelartefakt offen (P7-3).
- `[~]` Traceability BA→F→MT lückenlos und vorführbar; AT-KV-Akzeptanztests teamseitig.
- `[ ]` In Gesamtsystem integriert (GUI + Belege), Code gereviewt und gemergt (Phase 8 / 10).
---
## 8. Offene Punkte (nicht still aufgelöst)
| ID | Dokument / Stelle | Beschreibung | Vorschlag |
|----|-------------------|--------------|-----------|
| OP-1 | Pflichtenheft Klassendiagramm (Kap. 7.2) vs. GR-05 | Diagramm zeigt `KundeService ..> ProduktRepository`; GR-05-Text fordert Referenzprüfung über `BelegRepository`. Für die Löschsperre F-KV-04/MT-KV-11 ist das **BelegRepository** maßgeblich. | Im Code gegen `BelegRepository` prüfen (über `BelegReferenzPruefer` umgesetzt); Diagramm-Abhängigkeit als Doku-Inkonsistenz an Team/Prüfer melden. |
| OP-2 | Abgabe-Format | „max. 4 Dateien" für Testberichte bei 4 Modulen → Aufteilung 1 Datei/Modul **oder** 1 Sammeldatei? | Team-Entscheidung vor So 28.06; KV-Bericht entsprechend zuschneiden (P7-3). |
| OP-3 | Schnittstelle K3 (Lookup-Richtung) | Genaue Aufrufrichtung zwischen KV und Gruppe F für `isCustomerReferenced` final festzurren. | In P0-3 mit Gruppe F bestätigen. |
| OP-4 | Vertrag K1 vs. GUI-Übersicht (Gruppe E) | K1 enthält keine Methode zum Auflisten **aller** Kunden; `suchen("")` liefert bewusst eine leere Liste. Die `KundeAnsicht` kann die Gesamtliste so nicht über den Service beziehen. Kein Code-Fehler (K1 ist exakt umgesetzt), aber eine Vertragslücke. | Mit Gruppe E klären: entweder `List<Kunde> alle()` im `KundeService` ergänzen oder Konvention „leere Suche = alle Kunden" festlegen. Vor Phase 8 entscheiden. |
---
*Aktualisiere bei jeder Session die Zeile „Aktuelle Position" in Abschnitt 0 und die Status-Marker. Damit kann der Fortschritt jederzeit punktgenau aufgegriffen werden.*

View File

@ -1,117 +0,0 @@
---
title: "Modultestbericht Kundenverwaltung"
subtitle: "SE1 Team 2 Hochschule Mannheim · Modul Software Engineering 1"
author: "Christopher Lampert"
date: "26.06.2026"
lang: de-DE
geometry: "left=2.2cm,right=2.2cm,top=2cm,bottom=2cm"
fontsize: 10pt
mainfont: "Latin Modern Roman"
colorlinks: true
linkcolor: "blue"
urlcolor: "blue"
numbersections: false
header-includes:
- \setlength{\tabcolsep}{4pt}
- \renewcommand{\arraystretch}{1.12}
- \usepackage{etoolbox}
- \AtBeginEnvironment{longtable}{\small}
- \usepackage{newunicodechar}
- \newunicodechar{≥}{\ensuremath{\geq}}
- \newunicodechar{≤}{\ensuremath{\leq}}
---
# Modultestbericht Modul Kundenverwaltung (Gruppe H)
**Modul:** Software Engineering 1
**Team / Gruppe:** SE1 Team 2 Gruppe H (Kundenverwaltung), Package `de.hsmannheim.faktura.kunde`
**Version:** 1.0
**Stand:** 26.06.2026
**Autor / Tester:** Christopher Lampert
**Bezug:** Modultestplan (KV-Teil), Pflichtenheft v1.1, Lastenheft v1.1, Fahrplan Kundenverwaltung v1.1
Dieser Bericht dokumentiert die Durchführung und das Ergebnis der Modultests des Moduls **Kundenverwaltung**. Er weist nach, dass die im Modultestplan definierten Testfälle MT-KV-01 bis MT-KV-11 umgesetzt, ausgeführt und bestanden wurden, und belegt die geforderte Testabdeckung der Logikschicht (NF-TEST-03).
---
## Freigabeübersicht
| Funktion | Name | Rolle / Gruppe | Datum |
|--------------|----------------------------|------------------------------------|------------|
| Ersteller | Christopher Lampert | Autor / Tester, Gruppe H | 26.06.2026 |
| Prüfer | Oleg Akimenko | Gruppenleiter Gruppe H | _(offen)_ |
| Freigebender | SE1 Team 2 (Gruppenleiter) | Projektleitung / Freigabe | _(offen)_ |
---
## 1. Testgegenstand und Vorgehen
Geprüft wird die fachliche Logik der Kundenverwaltung die Anforderungen **F-KV-01 … F-KV-04**, die Geschäftsregel **GR-05** (Stammdatenschutz / Löschsperre) und **NF-ARCH-01** (Persistenz) über die öffentliche Schnittstelle des `KundeService`.
Die Tests sind als automatisierte JUnit-5-Tests **ohne GUI-Abhängigkeit** umgesetzt (NF-TEST-02) und in der Datei `KundeModultestTest.java` zusammengefasst. Jeder Testfall bildet **genau einen** Modultestplan-Fall ab (1:1) und trägt dessen Bezeichnung als `@DisplayName`, sodass das Testprotokoll unmittelbar aus dem Testlauf hervorgeht. Die Validierungs- und Persistenzschicht wird dabei real durchlaufen (echtes `KundeValidator`- und JSON-`KundeRepository`-Objekt je Test über `@TempDir`); lediglich die Beleg-Referenzprüfung der Löschsperre (GR-05) wird über das Interface `BelegReferenzPruefer` gesteuert. Die Ausführung erfolgt reproduzierbar über Maven (`mvn test`) bzw. den IntelliJ-Testrunner.
## 2. Testumgebung
| Aspekt | Festlegung |
|-------------------------------------|------------------------------------------------------------------------------|
| Programmiersprache | Java 17 (LTS); `maven.compiler.release=17` |
| Test-Framework | JUnit 5 (Jupiter) 5.10.2 |
| Build / Ausführung | Maven, `maven-surefire-plugin` 3.2.5 |
| Persistenz (im Test real genutzt) | Jackson Databind 2.17.1; lokale JSON-Datei je Test (`@TempDir`) |
| Abdeckungsmessung | IntelliJ IDEA Coverage Runner |
| Testdatei | `src/test/java/de/hsmannheim/faktura/kunde/service/KundeModultestTest.java` |
## 3. Testergebnisse
Alle elf Modultests wurden am **26.06.2026** ausgeführt und **bestanden**.
| Testfall | Testziel / Beschreibung | Anforderung | Ergebnis | Datum | Tester |
|----------|---------------------------------------------------|----------------------|-----------|------------|------------|
| MT-KV-01 | Kunde mit vollständigen Pflichtattributen anlegen | BA-KV-01 | bestanden | 26.06.2026 | C. Lampert |
| MT-KV-02 | Kunde ohne Firmenname bzw. Nachname anlegen | BA-KV-01 | bestanden | 26.06.2026 | C. Lampert |
| MT-KV-03 | Kunde ohne Straße anlegen | BA-KV-01 | bestanden | 26.06.2026 | C. Lampert |
| MT-KV-04 | Kunde mit ungültigem E-Mail-Format anlegen | BA-KV-01 | bestanden | 26.06.2026 | C. Lampert |
| MT-KV-05 | Vorhandenen Kunden bearbeiten | BA-KV-02 | bestanden | 26.06.2026 | C. Lampert |
| MT-KV-06 | Persistenz geänderter Kundendaten prüfen | BA-KV-02, NF-ARCH-01 | bestanden | 26.06.2026 | C. Lampert |
| MT-KV-07 | Kunde über Namen suchen | BA-KV-03 | bestanden | 26.06.2026 | C. Lampert |
| MT-KV-08 | Kunde über Kundennummer suchen | BA-KV-03 | bestanden | 26.06.2026 | C. Lampert |
| MT-KV-09 | Nicht vorhandenen Kunden suchen | BA-KV-03 | bestanden | 26.06.2026 | C. Lampert |
| MT-KV-10 | Nicht referenzierten Kunden löschen | BA-KV-04 | bestanden | 26.06.2026 | C. Lampert |
| MT-KV-11 | Referenzierten Kunden löschen | BA-KV-04, GR-05 | bestanden | 26.06.2026 | C. Lampert |
**Zusammenfassung:** 11 von 11 Testfällen bestanden (Pass-Quote 100 %); 0 fehlgeschlagen; 0 übersprungen.
## 4. Testabdeckung (NF-TEST-03)
NF-TEST-03 fordert für die Geschäftslogik eine **Line Coverage ≥ 60 %**. Gemessene Abdeckung der Logikschicht (`de.hsmannheim.faktura.kunde.service`) durch `KundeModultestTest`:
| Geltungsbereich | Klassen | Methoden | Zeilen (Line) | Branches |
|------------------------------------------|--------------|----------------|-----------------|-----------------|
| Logikschicht (`…kunde.service`) | 100 % (4/4) | 100 % (13/13) | 85 % (41/48) | 73 % (25/34) |
Mit **85 % Line Coverage** der Geschäftslogik bei **100 % abgedeckten Methoden** ist die geforderte Schwelle von 60 % deutlich übertroffen. **NF-TEST-03 ist erfüllt.**
## 5. Abdeckungsübersicht (Anforderung → Testfälle)
Übernommen aus dem Modultestplan (KV-Teil). Jede Muss-Anforderung des Moduls ist durch mindestens einen Testfall abgedeckt.
| Anforderung | Abgedeckte Testfälle |
|---------------------------|-----------------------|
| BA-KV-01 Kunde anlegen | MT-KV-01 bis MT-KV-04 |
| BA-KV-02 Kunde bearbeiten | MT-KV-05, MT-KV-06 |
| BA-KV-03 Kunde suchen | MT-KV-07 bis MT-KV-09 |
| BA-KV-04 Kunde löschen | MT-KV-10, MT-KV-11 |
| GR-05 Stammdatenschutz | MT-KV-11 |
| NF-ARCH-01 Persistenz | MT-KV-06 |
## 6. Fazit
Die fachlichen Anforderungen des Moduls Kundenverwaltung sind durch die Modultests MT-KV-01 bis MT-KV-11 vollständig abgedeckt und nachweislich erfüllt. Alle Tests bestehen (Pass-Quote 100 %), und die geforderte Testabdeckung der Logikschicht ist mit 85 % Line Coverage erreicht (NF-TEST-03). Die Traceability-Kette **BA-KV-0x → F-KV-0x → MT-KV-xx** ist über Modultestplan und diesen Bericht lückenlos belegbar.
---
## Änderungshistorie
| Version | Datum | Autor | Änderung |
|---------|------------|---------------------|---------------------------------------------------------------------------------------------------------------------------|
| 1.0 | 26.06.2026 | Christopher Lampert | Initiale Erstellung des Modultestberichts: Testergebnisse MT-KV-01…11, Coverage-Nachweis (NF-TEST-03), Abdeckungsübersicht. |

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
package de.hsmannheim.faktura.kunde.repository;
import de.hsmannheim.faktura.kunde.model.Kunde;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.File;
import java.nio.file.Path;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class KundeRepositoryJsonTest {
@Test
void persistenz_ueberlebt_neustart(@TempDir Path tempDir) {
File datei = tempDir.resolve("kunden.json").toFile();
// 1. Repository anlegen und einen Kunden speichern
KundeRepository repo1 = new KundeRepositoryJson(datei);
Kunde kunde = new Kunde();
kunde.setNachname("Mustermann");
kunde.setStrasse("Hauptstr. 1");
kunde.setPlz("01067"); // führende Null!
kunde.setOrt("Dresden");
long id = repo1.speichern(kunde);
// 2. Neues Repository auf dieselbe Datei = simulierter Neustart
KundeRepository repo2 = new KundeRepositoryJson(datei);
Optional<Kunde> geladen = repo2.findeById(id);
// 3. Kunde ist unverändert wiederhergestellt
assertTrue(geladen.isPresent(), "Kunde sollte nach Neustart vorhanden sein");
assertEquals("Mustermann", geladen.get().getNachname());
assertEquals("01067", geladen.get().getPlz(),
"Führende Null der PLZ muss erhalten bleiben");
assertEquals("Dresden", geladen.get().getOrt());
}
}

View File

@ -1,205 +0,0 @@
package de.hsmannheim.faktura.kunde.service;
import de.hsmannheim.faktura.kunde.model.Kunde;
import de.hsmannheim.faktura.kunde.repository.KundeRepositoryJson;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.io.TempDir;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Modultests der Kundenverwaltung (Gruppe H) Phase 6 des Fahrplans.
*
* <p>Diese Klasse überführt die fachliche Logik in exakt die elf im Modultestplan
* geforderten Testfälle MT-KV-01 MT-KV-11 (1:1-Abbildung). Jeder Test trägt den
* Modultestplan-Titel als {@code @DisplayName}, sodass der Testlauf direkt als
* Modultestbericht (Phase 7, P7-1) verwendbar ist.</p>
*
* <p>Die Tests laufen GUI-unabhängig (NF-TEST-02) gegen die echte Service-,
* Validator- und JSON-Repository-Schicht; nur die Beleg-Referenzprüfung der
* GR-05-Löschsperre wird über das Interface {@link BelegReferenzPruefer}
* gesteuert.</p>
*
* <p>Diese Datei ersetzt die zuvor getrennten Testklassen {@code KundeServiceTest},
* {@code KundeValidatorTest} und {@code KundeRepositoryJsonTest}; deren Abdeckung
* geht hier vollständig auf (vgl. P10-2 max. 4 Test-Dateien").</p>
*
* <p>Abgedeckte Anforderungen: BA-KV-01 BA-KV-04, GR-05, NF-ARCH-01.</p>
*/
@TestMethodOrder(MethodOrderer.MethodName.class)
@DisplayName("Modultests Kundenverwaltung (MT-KV-01 … MT-KV-11)")
class KundeModultestTest {
private KundeService service;
private File datei;
private boolean kundeIstReferenziert; // steuert die GR-05-Löschsperre im Test
private BelegReferenzPruefer belegPruefer;
@BeforeEach
void setUp(@TempDir Path tempDir) {
datei = tempDir.resolve("kunden.json").toFile();
kundeIstReferenziert = false;
belegPruefer = kundeId -> kundeIstReferenziert;
service = new KundeService(new KundeRepositoryJson(datei),
new KundeValidator(), belegPruefer);
}
/** Gültiger Kunde mit Firmenname (entspricht „Muster GmbH" aus MT-KV-01 / MT-KV-07). */
private Kunde musterKunde() {
Kunde k = new Kunde();
k.setFirmenname("Muster GmbH");
k.setStrasse("Hauptstr. 1");
k.setPlz("68159");
k.setOrt("Mannheim");
return k;
}
// ───────────────────────────── BA-KV-01: Kunde anlegen ─────────────────────────────
@Test
@DisplayName("MT-KV-01: Kunde mit vollständigen Pflichtattributen anlegen")
void mtKv01_kundeMitPflichtattributen_wirdGespeichert() { // BA-KV-01
long id = service.anlegen(musterKunde());
assertTrue(id > 0, "Es muss eine fortlaufende kundeId vergeben werden");
assertEquals(1, service.suchen("Muster").size(),
"Angelegter Kunde muss in der Kundenliste auffindbar sein");
}
@Test
@DisplayName("MT-KV-02: Kunde ohne Firmenname bzw. Nachname anlegen")
void mtKv02_ohneFirmennameUndNachname_wirdAbgelehnt() { // BA-KV-01
Kunde k = musterKunde();
k.setFirmenname(null); // nachname ist ohnehin null -> beide leer
assertThrows(ValidierungsException.class, () -> service.anlegen(k));
assertTrue(service.suchen("Muster").isEmpty(), "Es darf nichts gespeichert werden");
}
@Test
@DisplayName("MT-KV-03: Kunde ohne Straße anlegen")
void mtKv03_ohneStrasse_wirdAbgelehnt() { // BA-KV-01
Kunde k = musterKunde();
k.setStrasse(null);
assertThrows(ValidierungsException.class, () -> service.anlegen(k));
}
@Test
@DisplayName("MT-KV-04: Kunde mit ungültigem E-Mail-Format anlegen")
void mtKv04_ungueltigeEmail_wirdAbgelehnt() { // BA-KV-01
Kunde k = musterKunde();
k.setEmail("kunde@");
assertThrows(ValidierungsException.class, () -> service.anlegen(k));
}
// ──────────────────────────── BA-KV-02: Kunde bearbeiten ───────────────────────────
@Test
@DisplayName("MT-KV-05: Vorhandenen Kunden bearbeiten")
void mtKv05_telefonnummerAendern_wirdGespeichert() { // BA-KV-02
long id = service.anlegen(musterKunde());
Kunde k = service.finde(id).orElseThrow();
k.setTelefon("0621 12345");
service.bearbeiten(k);
assertEquals("0621 12345", service.finde(id).orElseThrow().getTelefon(),
"Geänderte Telefonnummer muss gespeichert und angezeigt werden");
}
@Test
@DisplayName("MT-KV-06: Persistenz geänderter Kundendaten prüfen")
void mtKv06_geaenderteDaten_ueberlebenNeuladen() { // BA-KV-02, NF-ARCH-01
// Kunde mit führender Null in der PLZ -> prüft zugleich den String-PLZ-Typ (Kap. 6.1.2)
Kunde k = new Kunde();
k.setNachname("Mustermann");
k.setStrasse("Hauptstr. 1");
k.setPlz("01067");
k.setOrt("Dresden");
long id = service.anlegen(k);
Kunde geladen = service.finde(id).orElseThrow();
geladen.setTelefon("0351 99999");
service.bearbeiten(geladen);
// Neues Repository/Service auf dieselbe Datei = simulierter Neustart
KundeService nachNeustart = new KundeService(new KundeRepositoryJson(datei),
new KundeValidator(), belegPruefer);
Kunde wieder = nachNeustart.finde(id).orElseThrow();
assertEquals("0351 99999", wieder.getTelefon(), "Geänderte Daten müssen erhalten bleiben");
assertEquals("01067", wieder.getPlz(), "Führende Null der PLZ muss erhalten bleiben");
assertEquals("Mustermann", wieder.getNachname());
}
// ──────────────────────────── BA-KV-03: Kunde suchen ───────────────────────────────
@Test
@DisplayName("MT-KV-07: Kunde über Namen suchen")
void mtKv07_sucheUeberNamen_findetKunden() { // BA-KV-03
service.anlegen(musterKunde()); // „Muster GmbH"
List<Kunde> treffer = service.suchen("Muster");
assertEquals(1, treffer.size());
assertEquals("Muster GmbH", treffer.get(0).getFirmenname());
}
@Test
@DisplayName("MT-KV-08: Kunde über Kundennummer suchen")
void mtKv08_sucheUeberKundennummer_findetKunden() { // BA-KV-03
long id = service.anlegen(musterKunde());
List<Kunde> treffer = service.suchen(String.valueOf(id));
assertEquals(1, treffer.size());
assertEquals(id, treffer.get(0).getKundeId());
}
@Test
@DisplayName("MT-KV-09: Nicht vorhandenen Kunden suchen")
void mtKv09_sucheOhneTreffer_istLeer() { // BA-KV-03
service.anlegen(musterKunde());
assertTrue(service.suchen("Gibtsnicht").isEmpty(),
"Ohne Treffer muss eine leere Liste zurückgegeben werden");
}
// ──────────────────────────── BA-KV-04: Kunde löschen ──────────────────────────────
@Test
@DisplayName("MT-KV-10: Nicht referenzierten Kunden löschen")
void mtKv10_nichtReferenzierterKunde_wirdEntfernt() { // BA-KV-04
long id = service.anlegen(musterKunde());
kundeIstReferenziert = false;
service.loeschen(id);
assertTrue(service.finde(id).isEmpty(), "Kunde muss entfernt sein");
assertTrue(service.suchen("Muster").isEmpty(),
"Gelöschter Kunde darf nicht mehr gefunden werden");
}
@Test
@DisplayName("MT-KV-11: Referenzierten Kunden löschen")
void mtKv11_referenzierterKunde_wirdAbgewiesen() { // BA-KV-04, GR-05
long id = service.anlegen(musterKunde());
kundeIstReferenziert = true;
assertThrows(LoeschsperreException.class, () -> service.loeschen(id));
assertTrue(service.finde(id).isPresent(),
"Referenzierter Kunde muss erhalten bleiben");
}
}

View File

@ -0,0 +1,99 @@
package de.hsmannheim.faktura.kunde.service;
import de.hsmannheim.faktura.kunde.model.Kunde;
import de.hsmannheim.faktura.kunde.repository.KundeRepository;
import de.hsmannheim.faktura.kunde.repository.KundeRepositoryJson;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
class KundeServiceTest {
private KundeService service;
private boolean kundeIstReferenziert; // steuert den BelegReferenzPruefer im Test
@BeforeEach
void setUp(@TempDir Path tempDir) {
File datei = tempDir.resolve("kunden.json").toFile();
KundeRepository repository = new KundeRepositoryJson(datei);
KundeValidator validator = new KundeValidator();
BelegReferenzPruefer belegPruefer = kundeId -> kundeIstReferenziert;
service = new KundeService(repository, validator, belegPruefer);
kundeIstReferenziert = false;
}
private Kunde gueltigerKunde() {
Kunde k = new Kunde();
k.setNachname("Mustermann");
k.setStrasse("Hauptstr. 1");
k.setPlz("68159");
k.setOrt("Mannheim");
return k;
}
@Test
void anlegen_vergibtIdUndPersistiert() { // BA-KV-01
long id = service.anlegen(gueltigerKunde());
assertTrue(id > 0);
assertEquals(1, service.suchen("Mustermann").size());
}
@Test
void anlegen_ungueltig_wirdNichtGespeichert() { // P3-4 im Service
Kunde k = gueltigerKunde();
k.setNachname(null);
assertThrows(ValidierungsException.class, () -> service.anlegen(k));
assertTrue(service.suchen("Mustermann").isEmpty());
}
@Test
void bearbeiten_aendertGespeichertenKunden() { // BA-KV-02
service.anlegen(gueltigerKunde());
Kunde k = service.suchen("Mustermann").get(0);
k.setTelefon("0621 12345");
service.bearbeiten(k);
assertEquals("0621 12345", service.suchen("Mustermann").get(0).getTelefon());
}
@Test
void suchen_ueberKundennummer_findet() { // BA-KV-03 / MT-KV-08
long id = service.anlegen(gueltigerKunde());
assertEquals(1, service.suchen(String.valueOf(id)).size());
}
@Test
void suchen_ohneTreffer_istLeer() { // BA-KV-03 / MT-KV-09
service.anlegen(gueltigerKunde());
assertTrue(service.suchen("Gibtsnicht").isEmpty());
}
@Test
void loeschen_nichtReferenziert_entfernt() { // BA-KV-04 / MT-KV-10
long id = service.anlegen(gueltigerKunde());
kundeIstReferenziert = false;
service.loeschen(id);
assertTrue(service.suchen("Mustermann").isEmpty());
}
@Test
void loeschen_referenziert_wirdAbgewiesen() { // BA-KV-04 / GR-05 / MT-KV-11
long id = service.anlegen(gueltigerKunde());
kundeIstReferenziert = true;
assertThrows(LoeschsperreException.class, () -> service.loeschen(id));
assertEquals(1, service.suchen("Mustermann").size()); // noch vorhanden
}
@Test
void finde_liefertAngelegtenKunden() { // K3
long id = service.anlegen(gueltigerKunde());
assertTrue(service.finde(id).isPresent());
assertEquals(id, service.finde(id).get().getKundeId());
assertTrue(service.finde(999L).isEmpty()); // unbekannte ID -> leer
}
}

View File

@ -0,0 +1,54 @@
package de.hsmannheim.faktura.kunde.service;
import de.hsmannheim.faktura.kunde.model.Kunde;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
class KundeValidatorTest {
private final KundeValidator validator = new KundeValidator();
private Kunde gueltigerKunde() {
Kunde k = new Kunde();
k.setNachname("Mustermann");
k.setStrasse("Hauptstr. 1");
k.setPlz("68159");
k.setOrt("Mannheim");
return k;
}
@Test
void gueltigerKunde_wirftNicht() {
assertDoesNotThrow(() -> validator.pruefe(gueltigerKunde()));
}
@Test
void ohneFirmennameUndNachname_wirdAbgelehnt() { // → MT-KV-02
Kunde k = gueltigerKunde();
k.setNachname(null);
assertThrows(ValidierungsException.class, () -> validator.pruefe(k));
}
@Test
void ohneStrasse_wirdAbgelehnt() { // → MT-KV-03
Kunde k = gueltigerKunde();
k.setStrasse(null);
assertThrows(ValidierungsException.class, () -> validator.pruefe(k));
}
@Test
void ungueltigeEmail_wirdAbgelehnt() { // → MT-KV-04
Kunde k = gueltigerKunde();
k.setEmail("kunde@");
assertThrows(ValidierungsException.class, () -> validator.pruefe(k));
}
@Test
void gueltigeEmail_wirftNicht() {
Kunde k = gueltigerKunde();
k.setEmail("kunde@example.com");
assertDoesNotThrow(() -> validator.pruefe(k));
}
}