40e8331695
Konvention: Eine Referenz traegt IMMER denselben Dateinamen wie das Ist- Ergebnis in output/ (nur anderes Verzeichnis). Referenz festlegen = Datei aus output/ unter gleichem Namen nach reference/ kopieren. - tests/README.md: neuer Abschnitt "Referenz-Namenskonvention (vereinheitlicht)" mit Regel/Tabelle/copy-Beispiel; Namenskonventions-Tabelle, Fixture-Vorlage (<modul>_tests.dxf statt <modul>_ref.dxf) und die Workflow-Referenzabschnitte angeglichen. - tests/conftest.py: kreisel_ref_dxf laedt reference/kreisel_tests.dxf (vorher kreisel_ref.dxf). - tests/test_omniflo.py: Referenz reference/omniflo_export.csv (vorher omniflo_export_reference.csv). - Referenzen abgenommen und in Git aufgenommen: reference/kreisel_tests.dxf (Umbenennung des Tippfehlers Kresel_ref.dxf), reference/omniflo_export.csv (aus geprueftem output/omniflo_export.csv). Der Batch-Vergleich --diff_references matchte schon immer ueber identische Basisnamen und bleibt unveraendert. Der Kreisel-Referenztest laeuft dadurch jetzt statt zu skippen. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
585 lines
23 KiB
Markdown
585 lines
23 KiB
Markdown
# Tests - SSG_LIB Testarchitektur
|
|
|
|
## Uebersicht
|
|
|
|
Die Tests folgen einer **zweistufigen Architektur**:
|
|
|
|
1. **LISP-Testrunner** (`.lsp`) — laufen in BricsCAD, erzeugen Ergebnisdateien
|
|
2. **Python-Validierung** (`.py`) — pruefen die Ergebnisse mit pytest + ezdxf
|
|
|
|
```
|
|
tests/alltests.json
|
|
|
|
|
v
|
|
BricsCAD Kommandozeile
|
|
| |
|
|
| SSG_RUN_ALL_TESTS |
|
|
| (fuehrt je Eintrag aus |
|
|
| alltests.json den passenden |
|
|
| TEST_<NAME> aus) |
|
|
| | |
|
|
v v |
|
|
tests/output/ |
|
|
<name>_results.json (immer) |
|
|
<name>_tests.dxf/.dwg (gemaess save)|
|
|
|
|
|
bin\run_tests.bat --check
|
|
|
|
|
pytest -v
|
|
|
|
|
test_<name>.py je Modul
|
|
```
|
|
|
|
## LISP-Unit-Tests fuer reine Standardfunktionen (`--lisp`)
|
|
|
|
Neben den zeichnungsbasierten Integrationstests gibt es **Unit-Tests fuer einfache
|
|
LISP-Standardfunktionen** — reine Funktionen ohne Zeichnungsdatenbank, Auswahlsaetze,
|
|
Dialoge oder Blockdateien (String-/Zahl-/Vektor-/Alist-Helfer). Sie funktionieren
|
|
analog zu den Python-Unittests: jeder Testfall vergleicht einen Funktionsaufruf gegen
|
|
ein erwartetes Ergebnis.
|
|
|
|
- **Testrunner**: `tests/test_unit.lsp` — Befehl `TEST_UNIT`, Mini-Framework mit
|
|
`tu-eq` (exakt), `tu-eqf` (Fliesskomma-Toleranz), `tu-true`, `tu-nil`.
|
|
- **Startskript**: `tests/test_unit.scr` — laedt SSG_LIB + die Tests, ruft `TEST_UNIT`
|
|
auf und beendet BricsCAD (pfadunabhaengig ueber `DXFMAKRO`).
|
|
- **Ergebnis**: Konsole (PASS/FAIL je Test) und `tests/output/unit_results.txt`
|
|
(letzte Zeile `RESULT: OK` / `RESULT: FAIL`).
|
|
|
|
Ausfuehrung ueber die Kommandozeile (startet BricsCAD headless):
|
|
|
|
```cmd
|
|
bin\run_tests.bat --lisp
|
|
```
|
|
|
|
`run_tests.bat --lisp` loescht das alte Ergebnis, startet BricsCAD mit `test_unit.scr`,
|
|
gibt danach `unit_results.txt` aus und liefert Exit-Code 1, wenn ein Test fehlschlaegt
|
|
oder kein Report erzeugt wurde.
|
|
|
|
Direkt in BricsCAD (SSG_LIB geladen):
|
|
|
|
```lisp
|
|
(load (strcat (getenv "DXFMAKRO") "/tests/test_unit.lsp"))
|
|
TEST_UNIT
|
|
```
|
|
|
|
Getestete Module: `ssg_core`, `ssg_lang`, `ssg_id`, `vf_core`, `export`,
|
|
`Gefaellestrecke`, `OmniModulInsert`, `KreiselInsert`.
|
|
|
|
## Zeichnungsbasierte Integrationstests
|
|
|
|
**Jedes Testmodul laeuft in einer eigenen, neuen Zeichnung** (statt die aktuelle zu
|
|
leeren/wiederzuverwenden). `SSG_RUN_ALL_TESTS` fragt beim Start interaktiv nach
|
|
dem gewuenschten Modus:
|
|
|
|
- **Kontroll-Modus (Default, Enter/Nein)**: Zeichnung wird gespeichert, per
|
|
`_.ZOOM _Extents` auf den Inhalt gezoomt und bleibt als eigener Tab offen —
|
|
der naechste Test startet in einer weiteren neuen Zeichnung. Am Ende des Laufs
|
|
sind alle Testzeichnungen gleichzeitig offen und direkt sichtbar. Sinnvoll,
|
|
wenn neue/geaenderte Testfaelle visuell geprueft werden sollen.
|
|
`c:EXPORTCSV`/`c:EXPORTSIVAS` laufen **nicht** automatisch mit — CSV/Sivas-
|
|
Export danach bei Bedarf manuell ueber `TEST_EXPORT_ALL`
|
|
(`tests/test_export_all.lsp`, Menuepunkt "Export CSV/Sivas ALL"), das alle
|
|
vorhandenen DXF/DWG-Dateien aus `tests/output/` einliest und je Datei
|
|
`<basis>_export.csv`/`<basis>_sivas.csv` erzeugt.
|
|
- **Automatik-Modus (Ja)**: Zeichnung wird gespeichert, direkt per
|
|
`c:EXPORTCSV`/`c:EXPORTSIVAS` exportiert (`<name>_tests_export.csv`/
|
|
`<name>_tests_sivas.csv`) und danach sofort wieder geschlossen. Kompletter
|
|
Lauf ohne manuellen Zusatzschritt, aber ohne gleichzeitige visuelle Kontrolle
|
|
aller Zeichnungen am Ende. Sinnvoll fuer reine CI-artige Validierung.
|
|
|
|
## alltests.json — Testregistry
|
|
|
|
Die Datei `tests/alltests.json` ist die zentrale Registry aller Test-Module.
|
|
`SSG_RUN_ALL_TESTS` liest sie beim Start — die Testliste ist **nicht** hartcodiert in `test_run_all.lsp`.
|
|
|
|
```json
|
|
[
|
|
{ "name": "kreisel", "save": "dxf", "module": "KreiselInsert" },
|
|
{ "name": "foerderer", "save": "dwg", "module": "VarioFoerderer" },
|
|
{ "name": "linienzug", "save": "dwg", "module": "VarioFoerderer" },
|
|
{ "name": "vfl_schema", "module": "VarioFoerderer" },
|
|
{ "name": "omniflo", "save": "dxf", "module": "OmniModulInsert" },
|
|
{ "name": "omniflo_strecke", "save": "dxf", "module": "OmniModulInsert" },
|
|
{ "name": "gefaellestrecke", "save": "dwg", "module": "Gefaellestrecke" },
|
|
{ "name": "mubea", "save": "dxf", "module": "KreiselInsert" },
|
|
{ "name": "hundm05", "save": "dxf", "module": "VarioFoerderer" }
|
|
]
|
|
```
|
|
|
|
Felder pro Eintrag:
|
|
|
|
| Feld | Typ | Bedeutung |
|
|
| --- | --- | --- |
|
|
| `name` | String | Basisname des Testmoduls (Pflicht) |
|
|
| `save` | `"dxf"` / `"dwg"` / `null` | Ob und als welches Format die Zeichnung gespeichert wird |
|
|
| `module` | String | LISP-Feature-Modul, das vor dem Test per `ssg-ensure` geladen wird |
|
|
| `disabled` | `true` | (optional) Schaltet den Eintrag ab: `SSG_RUN_ALL_TESTS` ueberspringt ihn komplett (kein Bauen/Speichern/Export) und gibt nur einen Hinweis auf der Konsole aus. Zum Reaktivieren das Feld entfernen. |
|
|
|
|
**JSON-Export laeuft immer** — unabhaengig vom `save`-Feld. Die Datei `<name>_results.json`
|
|
wird in `tests/output/` geschrieben, sobald der Test abgeschlossen ist.
|
|
|
|
**GUI-Aus waehrend des Laufs:** `SSG_RUN_ALL_TESTS` (und der Einzeltest `TEST_LINIENZUG`)
|
|
rufen `(ssg-gui-aus)` (ssg_core.lsp) auf, damit keine DCL-/Wizard-Dialoge den automatischen
|
|
Lauf blockieren; danach wird `(ssg-gui-an)` wieder gesetzt. Bei abgeschalteter GUI fallen die
|
|
Eingaben auf den Konsolen-/Mock-/Replay-Pfad zurueck. Interaktiver Betrieb (`FOERDERANLAGE`
|
|
etc.) ist davon unberuehrt (GUI standardmaessig an).
|
|
|
|
**Wann welches `save` verwenden:**
|
|
|
|
- `"dxf"` — wenn ein Python-Test (ezdxf) die Geometrie der Zeichnung pruefen soll
|
|
- `"dwg"` — wenn die Zeichnung zur manuellen Kontrolle oder als DWG-Referenz erhalten bleiben soll
|
|
- `null` (oder Feld weglassen) — wenn nur der JSON-Export benoetigt wird
|
|
|
|
## Ablauf fuer den Anwender
|
|
|
|
1. **BricsCAD starten** (ueber `bin\start_briscad.bat`) und die LISP-Testrunner ausfuehren (siehe Abschnitt "LISP-Tests in BricsCAD ausfuehren"). Die Testrunner erzeugen Bloecke in der Zeichnung und speichern Ergebnisse nach `tests/output/`.
|
|
|
|
2. **Optische Kontrolle** in BricsCAD — pruefen ob die erzeugten Bloecke korrekt aussehen (Positionen, Drehungen, Beschriftungen). Jede Testzeichnung bleibt als eigener Tab offen (auf den Inhalt gezoomt) und kann direkt visuell inspiziert werden.
|
|
|
|
3. **Kommandozeile**: Ergebnisse validieren:
|
|
- `bin\run_tests.bat --check` — pytest prueft die Ergebnisse aus `output/` gegen Testdefinitionen und Referenzdaten (optional: einzelnes Modul, z.B. `--check test_kreisel.py`)
|
|
- `bin\run_tests.bat --diff_references` — vergleicht die CSVs in `output/` gegen `reference/` (gleicher Dateiname, siehe Abschnitt "Referenz-Namenskonvention") und oeffnet bei Unterschieden das Diff-Tool (meld); optional eine einzelne Datei, z.B. `--diff_references kreisel_tests_export.csv`
|
|
- Referenz aktualisieren (nach geprueftem Lauf): die betreffende(n) Datei(en) aus `output/` unter DEMSELBEN Namen nach `reference/` kopieren (es gibt keinen eigenen Schalter dafuer)
|
|
|
|
## Verzeichnisstruktur
|
|
|
|
```
|
|
tests/
|
|
conftest.py # Gemeinsame pytest-Fixtures (Pfade, JSON/DXF-Laden)
|
|
create_testbase.py # Erzeugt Basis-DXF (optional, wird nicht mehr benoetigt)
|
|
requirements.txt # Python-Abhaengigkeiten (ezdxf, pytest)
|
|
test_run_all.lsp # Fuehrt alle Tests aus: C:SSG_RUN_ALL_TESTS
|
|
test_kreisel.lsp # LISP-Testrunner: C:TEST_KREISEL
|
|
test_kreisel.py # pytest-Validierung der Kreisel-Ergebnisse
|
|
test_foerderer.lsp # LISP-Testrunner: C:TEST_FOERDERER
|
|
test_omniflo.lsp # LISP-Testrunner: C:TEST_OMNIFLO
|
|
test_omniflo.py # pytest-Validierung der Omniflo-Ergebnisse
|
|
test_omniflo_strecke.lsp # LISP-Testrunner: C:TEST_OMNIFLO_STRECKE (Streckenzug)
|
|
test_omniflo_strecke.py # pytest-Validierung des Omniflo-Streckenzugs
|
|
test_export_all.lsp # LISP-Testrunner: C:TEST_EXPORT_ALL (manuell, nicht in alltests.json)
|
|
test_foerderer.py # pytest-Validierung Foerderer (Status/Mathematik/CSV/Sivas)
|
|
test_gefaellestrecke.py # pytest-Validierung Gefaellestrecke
|
|
test_mubea.py # pytest-Validierung Mubea-Gesamtmodell
|
|
test_hundm05.lsp # LISP: baut die 5 HundM-Ketten aus ihrer
|
|
# Spec (testdata/hundm05.json) - ruft
|
|
# vsp-bau-datei, keine eigene Bau-Logik
|
|
test_hundm05.py # pytest: die so gebaute Anlage pruefen
|
|
test_hm_recformat.lsp # LISP: dieselben Ketten aus dem ROHEN
|
|
# Journal der Kundenzeichnung - der
|
|
# Regressionstest fuers Aufzeichnungs-
|
|
# format (in alltests.json abgeschaltet,
|
|
# baut sonst dieselbe Geometrie zweimal)
|
|
test_hm_recformat.py # pytest-Validierung dazu
|
|
test_vf_geometrie.py # pytest: die GEBAUTE Geometrie gegen
|
|
# reference/hundm05_attribute.json - Attribute,
|
|
# Bausteine, Einfuegepunkt (faengt eine
|
|
# vertauschte vfl-acc-*-Reihenfolge)
|
|
test_vf_spec.lsp # LISP-Unittest: Spec-Uebersetzer (vsp-journal),
|
|
# je Glied-Typ + die 5 echten HundM-Ketten
|
|
# gegen ihr aufgezeichnetes Journal
|
|
test_vf_spec.py # pytest: Rundlauf Journal->Spec->Journal, die
|
|
# Spec-Testdaten, und die Ergebnisse von
|
|
# VF_SPEC_BAU (letztere brauchen BricsCAD)
|
|
test_vf_journal_grammatik.py # pytest ohne CAD: Journal-Dekoder aus
|
|
# lib/vf_journal_export.py gegen handgebaute
|
|
# Journale (Linie-VF, gewinkelter Erstkoerper)
|
|
test_vf_headless_statisch.py # pytest ohne CAD: statischer Waechter, dass
|
|
# im VF-Bau-Pfad kein alert/get*/ssget neu
|
|
# auftaucht und der Headless-Riegel an allen
|
|
# vfl-in-*-Wrappern sitzt
|
|
test_unit.lsp / .scr # LISP-Unit-Tests: C:TEST_UNIT (ueber --lisp)
|
|
testdata/
|
|
kreisel_tests.json # Testfall-Definitionen fuer Kreisel
|
|
omniflo_tests.json # Testfall-Definitionen fuer Omniflo
|
|
omniflo_strecke_tests.json # Streckenzug: 4 Geraden + 2 Boegen + 1 Weiche (7 Elemente)
|
|
hm_recformat.json # Aufzeichnung: rohes Journal der 5 Ketten
|
|
hundm05.json # daraus abgeleitete Spec (wird erweitert)
|
|
foerderer_tests.json / mubea.json / ...
|
|
output/ # Ergebnisse aus BricsCAD (nicht in Git)
|
|
<name>_results.json # JSON-Ergebnisse pro Testmodul (immer)
|
|
<name>_tests.dxf/.dwg # Zeichnung pro Testmodul (gemaess save in alltests.json)
|
|
export_all_results.json # nur nach manuellem TEST_EXPORT_ALL-Lauf
|
|
<basis>_export.csv # EXPORTCSV je Quelldatei, nur nach TEST_EXPORT_ALL
|
|
<basis>_sivas.csv # EXPORTSIVAS je Quelldatei, nur nach TEST_EXPORT_ALL
|
|
reference/ # Abgenommene Referenzdaten (in Git): *_results.json,
|
|
... # *_tests_export.csv / *_tests_sivas.csv, *_tests.dxf,
|
|
... # omniflo_export.csv, export_raw.json
|
|
```
|
|
|
|
## Referenz-Namenskonvention (vereinheitlicht)
|
|
|
|
**Eine Referenz traegt IMMER denselben Dateinamen wie das zugehoerige Ist-Ergebnis
|
|
in `output/`.** Der einzige Unterschied ist das Verzeichnis:
|
|
|
|
```
|
|
output/<datei> # Ist-Ergebnis (bei jedem Lauf neu, nicht in Git)
|
|
reference/<datei> # abgenommener Soll-Stand (identischer Name, in Git)
|
|
```
|
|
|
|
Damit gilt durchgehend: **Referenz festlegen = Datei aus `output/` nach `reference/`
|
|
kopieren** - kein Umbenennen, kein Suffix. Beispiele:
|
|
|
|
| Ist-Ergebnis in `output/` | Referenz in `reference/` |
|
|
| --- | --- |
|
|
| `kreisel_tests.dxf` | `kreisel_tests.dxf` |
|
|
| `kreisel_tests_export.csv` | `kreisel_tests_export.csv` |
|
|
| `foerderer_results.json` | `foerderer_results.json` |
|
|
| `omniflo_export.csv` | `omniflo_export.csv` |
|
|
|
|
```cmd
|
|
copy tests\output\kreisel_tests.dxf tests\reference\kreisel_tests.dxf
|
|
```
|
|
|
|
Frueher gab es zwei Ausreisser, die bewusst auf dieses Schema gezogen wurden
|
|
(nicht mehr verwenden):
|
|
|
|
- `reference/kreisel_ref.dxf` (bzw. der Tippfehler `Kresel_ref.dxf`) -> jetzt
|
|
`reference/kreisel_tests.dxf`
|
|
- `reference/omniflo_export_reference.csv` -> jetzt `reference/omniflo_export.csv`
|
|
|
|
Die pytest-Fixtures und -Checks suchen ausschliesslich nach dem vereinheitlichten
|
|
Namen; fehlt die Referenz, wird der Vergleich mit einem Hinweis uebersprungen
|
|
(kein Fehler).
|
|
|
|
## Workflow
|
|
|
|
### 1. LISP-Tests in BricsCAD ausfuehren
|
|
|
|
BricsCAD starten (ueber `bin\start_briscad.bat`) und Module laden:
|
|
|
|
```lisp
|
|
(load (strcat (getenv "DXFMAKRO") "/Lisp/ssg_load.lsp"))
|
|
```
|
|
|
|
Dann alle Tests auf einmal ausfuehren:
|
|
|
|
```lisp
|
|
;; Alle Tests ausfuehren (empfohlen)
|
|
(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp"))
|
|
SSG_RUN_ALL_TESTS
|
|
```
|
|
|
|
`SSG_RUN_ALL_TESTS` liest die Testliste aus `tests/alltests.json` und fuehrt fuer jedes Modul aus:
|
|
|
|
1. Zeichnung leeren (ERASE ALL + PURGE x5) — saubere Basis fuer jeden Test
|
|
2. `test_<name>.lsp` laden und `TEST_<NAME>` ausfuehren
|
|
3. JSON-Export aufrufen: `<name>:export-results` — **immer**, unabhaengig von `save`
|
|
4. Zeichnung speichern — nur wenn `"save"` in `alltests.json` gesetzt ist (`"dxf"` oder `"dwg"`)
|
|
5. Bei Fehler: weiter mit naechstem Test (`vl-catch-all-apply`)
|
|
|
|
**Einzeltest** (z.B. nur Kreisel pruefen):
|
|
|
|
```lisp
|
|
;; Test-Datei laden und Befehl ausfuehren
|
|
(load (strcat (getenv "DXFMAKRO") "/tests/test_kreisel.lsp"))
|
|
TEST_KREISEL
|
|
;; JSON-Export manuell aufrufen:
|
|
(kreisel:export-results (strcat (getenv "DXFMAKRO") "/tests/output"))
|
|
```
|
|
|
|
**Unterschied SSG_RUN_ALL_TESTS vs. Einzeltest:**
|
|
|
|
| | SSG_RUN_ALL_TESTS | Einzeltest |
|
|
| --- | --- | --- |
|
|
| Testliste | aus `alltests.json` | manuell gewaehlter Test |
|
|
| Zeichnung leeren | automatisch vor jedem Test | nein (Zeichnung bleibt) |
|
|
| JSON-Export | automatisch nach jedem Test | manuell aufrufen |
|
|
| DXF/DWG speichern | gemaess `save` in `alltests.json` | manuell (SAVEAS / DXFOUT) |
|
|
| Fehlerisolation | ja (Fehler unterbricht nicht weitere Tests) | nein |
|
|
|
|
### 2. Python-Validierung ausfuehren
|
|
|
|
```cmd
|
|
bin\run_tests.bat --check
|
|
```
|
|
|
|
Oder fuer ein einzelnes Testmodul:
|
|
|
|
```cmd
|
|
bin\run_tests.bat --check test_kreisel.py
|
|
```
|
|
|
|
Die Python-Tests pruefen:
|
|
- **Attribut-Werte** gegen die Testdefinitionen (JSON)
|
|
- **DXF-Geometrie** mit ezdxf (Bloecke, Positionen, Radien)
|
|
- **Referenz-Vergleich** gegen abgenommene Referenz-DXF
|
|
- **CSV-Export** ueber `lib/export_csv.py` (Omniflo: Spalten, Merkmale, Sum-Zeile, Datentypen)
|
|
|
|
Tests, deren Eingabedaten fehlen (z.B. kein BricsCAD-Lauf), werden automatisch uebersprungen (`pytest.skip`).
|
|
|
|
### 3. Referenz erstellen/aktualisieren
|
|
|
|
Nach einem erfolgreichen, geprueften Testlauf die betreffende(n) Ergebnisdatei(en)
|
|
manuell aus `output/` unter DEMSELBEN Dateinamen nach `reference/` kopieren (nur bei
|
|
bestandenen Tests, siehe Abschnitt "Referenz-Namenskonvention"). Es gibt keinen
|
|
eigenen Batch-Schalter dafuer.
|
|
|
|
```cmd
|
|
copy tests\output\<datei> tests\reference\<datei>
|
|
```
|
|
|
|
Beispiel (Kreisel-DXF und Omniflo-CSV als Referenz festlegen):
|
|
|
|
```cmd
|
|
copy tests\output\kreisel_tests.dxf tests\reference\kreisel_tests.dxf
|
|
copy tests\output\omniflo_export.csv tests\reference\omniflo_export.csv
|
|
```
|
|
|
|
Zum Vergleich der aktuellen CSVs gegen die Referenz (mit Diff-Tool meld):
|
|
|
|
```cmd
|
|
bin\run_tests.bat --diff_references
|
|
```
|
|
|
|
## Neuen Test erstellen
|
|
|
|
### Schritt 1: Testdaten definieren (JSON)
|
|
|
|
Neue Testfaelle in `testdata/<modul>_tests.json` eintragen. Das Format ist ein **flaches JSON-Array** (kompatibel mit `omni:load-json`).
|
|
|
|
**Kreisel-Beispiel** (`kreisel_tests.json`):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"id": "KR_Insert_Neu",
|
|
"function": "insert",
|
|
"x": 5000, "y": 5000, "z": 2000,
|
|
"abstand": 5000,
|
|
"rotation": 0.0,
|
|
"typ": "STANDARD",
|
|
"expect_block_prefix": "KREISEL_",
|
|
"expect_hoehe": "2000",
|
|
"expect_kreiselart": "STANDARD"
|
|
}
|
|
]
|
|
```
|
|
|
|
Felder:
|
|
- `id` — Eindeutiger Name des Testfalls
|
|
- `function` — `"insert"` oder `"connect"`
|
|
- Eingabeparameter (`x`, `y`, `z`, `abstand`, `rotation`, `typ` fuer Insert; `start_x/y/z`, `end_x/y/z`, `typ` fuer Connect)
|
|
- `expect_*` — Erwartete Ergebniswerte (fuer Python-Validierung)
|
|
|
|
**Omniflo-Beispiel** (`omniflo_tests.json`):
|
|
|
|
```json
|
|
[
|
|
{
|
|
"sivasnr": "834372001",
|
|
"type": "bogen",
|
|
"description": "Bogen 90 Grad R200",
|
|
"hoehe": 2000,
|
|
"drehung": 0
|
|
}
|
|
]
|
|
```
|
|
|
|
**Foerderer-Beispiel** (`foerderer_tests.json`):
|
|
|
|
```json
|
|
[
|
|
{ "y_abstand": 800 },
|
|
{
|
|
"test_id": "VF_Auf_2000_Rechts",
|
|
"richtung": "Auf",
|
|
"deltaL": 7000,
|
|
"deltaH": 2000,
|
|
"seite": "rechts",
|
|
"winkel": 27,
|
|
"gf_verteilung": "vorne"
|
|
}
|
|
]
|
|
```
|
|
|
|
Felder:
|
|
|
|
- `test_id` — Eindeutiger Name des Testfalls
|
|
- `richtung` — `"Auf"` oder `"Ab"`
|
|
- `deltaL`, `deltaH` — Horizontal-/Hoehendistanz in mm
|
|
- `seite` *(optional, Default `"links"`)* — `"links"` oder `"rechts"`, steuert AS-/ES-Seite (`SEITE_AS`/`SEITE_ES`-Attribut)
|
|
- `winkel` *(optional)* — erzwingt einen bestimmten Kandidatenwinkel statt des automatisch gewaehlten kleinsten gueltigen Winkels; muss ein gueltiger Wert aus der `bogen_winkel`-Kandidatenliste sein, sonst wird der Testfall `NICHT_GEBAUT`
|
|
- `gf_verteilung` *(optional, Default `"gleichmaessig"`)* — `"gleichmaessig"` (50/50 auf Einlauf/Auslauf), `"vorne"` (alles am Einlauf) oder `"hinten"` (alles am Auslauf)
|
|
|
|
### Schritt 2: LISP-Testrunner erweitern (falls neues Modul)
|
|
|
|
Fuer ein neues Modul eine neue `.lsp`-Datei erstellen nach dem Muster:
|
|
|
|
```lisp
|
|
;; test_<modul>.lsp
|
|
;; Konvention: Basisname <modul> bestimmt Befehl, DXF und Export-Funktion
|
|
|
|
;; Export-Funktion (wird von test_run_all.lsp aufgerufen)
|
|
(defun <modul>:export-results (tests-out-dir / out-json f first)
|
|
(if (null *<modul>-test-results*)
|
|
(princ "\n Keine <modul>-Ergebnisse vorhanden.")
|
|
(progn
|
|
(vl-mkdir tests-out-dir)
|
|
(setq out-json (strcat tests-out-dir "/<modul>_results.json"))
|
|
;; ... JSON-Array schreiben ...
|
|
)
|
|
)
|
|
)
|
|
|
|
(defun c:TEST_<MODUL> (/ ...)
|
|
(ssg-start "TEST_<MODUL>" '(("OSMODE") ("ATTREQ") ("ATTDIA")))
|
|
(setvar "OSMODE" 0)
|
|
(setvar "ATTREQ" 0)
|
|
(setvar "ATTDIA" 0)
|
|
|
|
;; 1. Testdaten laden
|
|
(setq testfaelle (omni:load-json
|
|
(strcat (getenv "DXFMAKRO") "/tests/testdata/<modul>_tests.json")))
|
|
|
|
;; 2. Testfaelle ausfuehren, Ergebnisse sammeln
|
|
(foreach eintrag testfaelle
|
|
;; ... Script-Funktion aufrufen, Ergebnis pruefen ...
|
|
)
|
|
|
|
;; 3. Ergebnisse in globaler Variable speichern
|
|
(setq *<modul>-test-results* (reverse results-list))
|
|
|
|
(ssg-end)
|
|
)
|
|
```
|
|
|
|
Dann den Basisnamen in `tests/alltests.json` eintragen:
|
|
|
|
```json
|
|
{ "name": "<modul>", "save": "dxf" }
|
|
```
|
|
|
|
`"save"` waehlen je nach Bedarf (`"dxf"`, `"dwg"` oder `null`).
|
|
`test_run_all.lsp` leitet alle Namen aus dem `"name"`-Feld ab — **nichts** in `test_run_all.lsp` aendern.
|
|
|
|
### Namenskonventionen (werden von test_run_all.lsp automatisch abgeleitet)
|
|
|
|
Aus dem Basisnamen `<name>` in `alltests.json` entstehen durch Konvention:
|
|
|
|
| Element | Schema | Beispiel fuer `"name": "kreisel"` |
|
|
| --- | --- | --- |
|
|
| LISP-Datei | `tests/test_<name>.lsp` | `tests/test_kreisel.lsp` |
|
|
| BricsCAD-Befehl | `TEST_<NAME>` (Grossbuchstaben) | `TEST_KREISEL` |
|
|
| Export-Funktion | `<name>:export-results` | `kreisel:export-results` |
|
|
| JSON-Ergebnis | `output/<name>_results.json` | `output/kreisel_results.json` |
|
|
| DXF/DWG-Datei | `output/<name>_tests.dxf/.dwg` | `output/kreisel_tests.dxf` |
|
|
| Referenz (Soll) | `reference/<gleicher Name wie output>` | `reference/kreisel_tests.dxf` |
|
|
|
|
Die Export-Funktion **muss** exakt so heissen: `<name>:export-results` (Namespace-Notation mit Doppelpunkt).
|
|
Sie nimmt genau einen Parameter entgegen: den Pfad zum Output-Verzeichnis.
|
|
|
|
Wichtig:
|
|
|
|
- `omni:load-json` erwartet ein **flaches JSON-Array** mit flachen Objekten (kein Nesting)
|
|
- `omni:val` liest Werte aus den geladenen Eintraegen
|
|
- Script-Funktionen (z.B. `kreisel-insert-script`) muessen **ohne User-Interaktion** funktionieren
|
|
|
|
### Schritt 3: Python-Validierung erstellen
|
|
|
|
Neue `test_<modul>.py` erstellen:
|
|
|
|
```python
|
|
import pytest
|
|
|
|
class TestModulAttributes:
|
|
"""Prueft Attribute gegen Testdefinitionen."""
|
|
|
|
def test_all_executed(self, <modul>_results):
|
|
"""Alle Testfaelle muessen ausgefuehrt worden sein."""
|
|
# ...
|
|
|
|
def test_attribute_values(self, <modul>_testdata, <modul>_results):
|
|
"""Attributwerte muessen mit Erwartungen uebereinstimmen."""
|
|
# ...
|
|
|
|
class TestModulGeometry:
|
|
"""Prueft DXF-Geometrie mit ezdxf."""
|
|
|
|
def test_blocks_exist(self, <modul>_dxf):
|
|
"""Bloecke muessen im Modelspace vorhanden sein."""
|
|
# ...
|
|
|
|
class TestModulReference:
|
|
"""Vergleicht gegen Referenz."""
|
|
|
|
def test_matches_reference(self, <modul>_dxf, <modul>_ref_dxf):
|
|
# ...
|
|
```
|
|
|
|
### Schritt 4: Fixtures in conftest.py ergaenzen
|
|
|
|
Neue Fixtures fuer Testdaten, Ergebnisse und DXF in `conftest.py` hinzufuegen:
|
|
|
|
```python
|
|
@pytest.fixture
|
|
def <modul>_testdata():
|
|
path = os.path.join(_testdata_dir(), "<modul>_tests.json")
|
|
return _load_json(path)
|
|
|
|
@pytest.fixture
|
|
def <modul>_results():
|
|
path = os.path.join(_output_dir(), "<modul>_results.json")
|
|
if not os.path.exists(path):
|
|
pytest.skip("<modul>_results.json nicht vorhanden")
|
|
return _load_json(path)
|
|
|
|
@pytest.fixture
|
|
def <modul>_dxf():
|
|
path = os.path.join(_output_dir(), "<modul>_tests.dxf")
|
|
if not os.path.exists(path):
|
|
pytest.skip("<modul>_tests.dxf nicht vorhanden")
|
|
return ezdxf.readfile(path)
|
|
|
|
@pytest.fixture
|
|
def <modul>_ref_dxf():
|
|
# Konvention: Referenz = GLEICHER Dateiname wie das Ist-Ergebnis in output/.
|
|
path = os.path.join(_reference_dir(), "<modul>_tests.dxf")
|
|
if not os.path.exists(path):
|
|
pytest.skip("reference/<modul>_tests.dxf nicht vorhanden - Referenz noch "
|
|
"nicht festgelegt (output/<modul>_tests.dxf nach reference/ kopieren)")
|
|
return ezdxf.readfile(path)
|
|
```
|
|
|
|
## Testklassen
|
|
|
|
### test_kreisel.py
|
|
|
|
| Klasse | Prueft |
|
|
|---|---|
|
|
| `TestKreiselAttributes` | Attribute (KREISELART, HOEHE), Block-Prefixe, Status |
|
|
| `TestKreiselGeometry` | DXF-Bloecke, Positionen, Kreis-Radien (400mm) |
|
|
| `TestKreiselReference` | Block-Anzahl und -Typen gegen Referenz-DXF |
|
|
|
|
### test_omniflo.py
|
|
|
|
| Klasse | Prueft |
|
|
|---|---|
|
|
| `TestOmnifloExportUnit` | Mock-Export ueber `lib/export_csv.py`: Merkmale, Datentypen, Sum-Zeile, Vollstaendigkeit (ohne BricsCAD) |
|
|
| `TestOmnifloResults` | omniflo_results.json aus BricsCAD: Testfaelle vollstaendig, Status OK, Hoehe |
|
|
| `TestOmnifloReferenceCSV` | CSV-Export aus `lib/export_csv.py` gegen abgenommene Referenz-CSV |
|
|
|
|
### test_omniflo_strecke.py
|
|
|
|
Streckenzug **4 Geraden -> 180-Grad-Kurve (4x 45-Grad-Bogen) -> 4 Geraden**.
|
|
Die Geometrie wird ohne BricsCAD direkt aus `omniflo_strecke_tests.json` geprueft.
|
|
|
|
| Klasse | Prueft |
|
|
|---|---|
|
|
| `TestStreckeStruktur` | 4+4+4 = 12 Elemente, Reihenfolge der Gruppen, Typen |
|
|
| `TestStreckeKatalog` | Bogen-SivasNummern existieren in `omniflo_boegen.json` (Radius/Winkel) |
|
|
| `TestStreckeGeometrie` | Lueckenlose Verkettung, Kurvensumme 180 Grad, gemeinsamer Bogen-Mittelpunkt |
|
|
| `TestStreckeResults` | omniflo_strecke_results.json aus BricsCAD: Elemente vollstaendig, Status OK |
|
|
|
|
## Umgebungsvariablen
|
|
|
|
Werden von `bin\setenv.bat` gesetzt. Fuer Tests relevant:
|
|
|
|
| Variable | Beschreibung |
|
|
|---|---|
|
|
| `DXFMAKRO` | Projektwurzel |
|
|
| `DXFM_TESTS` | tests/-Verzeichnis |
|
|
| `DXFM_TESTDATA` | testdata/-Verzeichnis |
|
|
| `DXFM_TESTOUT` | output/-Verzeichnis |
|
|
| `DXFM_TESTREF` | reference/-Verzeichnis |
|
|
| `DXFM_OMNIFLO` | Pfad zu Omniflo-DXF-Dateien |
|