9.4 KiB
Testkonzept SSG_LIB - Hybrid AutoLISP + Python
Uebersicht
Die SSG_LIB AutoLISP-Makros werden ueber einen zweistufigen Hybrid-Ansatz getestet:
- AutoLISP (in BricsCAD): Liest JSON-Testfaelle, fuehrt die Funktionen aus, schreibt Ergebnisse als JSON und DXF/DWG.
- Python (pytest + ezdxf): Validiert die Ergebnisse automatisch gegen erwartete Werte und optionale Referenzdaten.
Python (pytest) AutoLISP (BricsCAD) Python (pytest)
=============== ==================== ===============
Testfall-Definitionen --> Ausfuehrung der --> Validierung:
als JSON bereitstellen LISP-Funktionen - JSON-Ergebnisse
+ DXF/DWG + results.json - DXF-Geometrie
- Referenz-Vergleich
Verzeichnisstruktur
tests/
├── alltests.json # Zentrale Testregistry (welche Module + Speicherformat)
├── test_run_all.lsp # C:SSG_RUN_ALL_TESTS - fuehrt alle Tests aus
├── test_kreisel.lsp # C:TEST_KREISEL - Kreisel-Testrunner
├── test_foerderer.lsp # C:TEST_FOERDERER - Variofoerderer-Testrunner
├── test_kseinaus.lsp # C:TEST_KSEINAUS - KreiselEinAus-Testrunner
├── test_omniflo.lsp # C:TEST_OMNIFLO - Omniflo-Testrunner
├── conftest.py # pytest Fixtures
├── test_kreisel.py # pytest Kreisel-Validierung
├── test_omniflo.py # pytest Omniflo-Validierung
├── create_testbase.py # Hilfsskript (optional, i.d.R. nicht benoetigt)
├── requirements.txt # Python-Abhaengigkeiten (ezdxf, pytest)
├── testdata/ # JSON-Testfall-Definitionen (versioniert)
│ ├── kreisel_tests.json
│ ├── foerderer_tests.json
│ └── omniflo_tests.json
├── reference/ # Abgenommene Referenzdaten (versioniert)
│ └── omniflo_export_reference.csv
└── output/ # Generierte Ergebnisse (nicht in Git)
├── kreisel_results.json
├── kreisel_tests.dxf
├── foerderer_results.json
├── foerderer_tests.dwg
├── kseinaus_results.json
├── omniflo_results.json
└── omniflo_tests.dxf
Testregistry (alltests.json)
Die Datei tests/alltests.json ist die zentrale Registry aller Testmodule.
SSG_RUN_ALL_TESTS liest sie beim Start — die Testliste ist nicht hartcodiert.
[
{ "name": "kreisel", "save": "dxf", "module": "KreiselInsert" },
{ "name": "foerderer", "save": "dwg", "module": "VarioFoerderer" },
{ "name": "kseinaus", "save": null, "module": "VarioFoerderer" },
{ "name": "omniflo", "save": "dxf", "module": "OmniModulInsert" }
]
| Feld | Typ | Bedeutung |
|---|---|---|
name |
String | Basisname des Testmoduls (Pflicht) |
save |
"dxf" / "dwg" / null |
Speicherformat der Zeichnung |
module |
String | LISP-Modul (wird von ssg-ensure geladen) |
Aus dem name werden alle Dateinamen abgeleitet:
| Element | Schema | Beispiel (kreisel) |
|---|---|---|
| LISP-Datei | tests/test_<name>.lsp |
tests/test_kreisel.lsp |
| BricsCAD-Befehl | TEST_<NAME> |
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 |
Schritt 1: Testfaelle definieren (JSON)
Jedes Modul hat eine eigene JSON-Datei in tests/testdata/. Format: flaches JSON-Array
(kompatibel mit omni:load-json). Kein Nesting, keine Wrapper-Objekte.
Kreisel-Format (kreisel_tests.json)
[
{
"id": "KR_Kreuz_Q1_0Grad",
"function": "insert",
"x": 500, "y": 500, "z": 2500,
"abstand": 2000,
"rotation": 0.0,
"typ": "STANDARD",
"expect_block_prefix": "KREISEL_",
"expect_hoehe": "2500",
"expect_kreiselart": "STANDARD"
}
]
Felder:
id— Eindeutiger Testfall-Namefunction—"insert"oder"connect"- Eingabeparameter:
x,y,z,abstand,rotation,typ expect_*— Erwartete Ergebniswerte (fuer Python-Validierung)
Foerderer-Format (foerderer_tests.json)
[
{ "y_abstand": 400 },
{
"test_id": "VF_Auf_0",
"richtung": "Auf",
"deltaL": 7000,
"deltaH": 0
}
]
- Erster Eintrag (ohne
test_id): Konfiguration (y_abstandzwischen Foerderern) - Felder:
test_id,richtung("Auf"/"Ab"),deltaL,deltaH - Ergebnisstatus:
GEBAUT,NICHT_GEBAUT,GEOMETRISCH_UNMOEGLICH
Omniflo-Format (omniflo_tests.json)
[
{
"id": "821104025",
"type": "bogen",
"sivasnr": "821104025",
"x": 219.4, "y": 223.06,
"hoehe": 2000,
"drehung": 0.0,
"description": "APB 110 R 550/22,5 – 84/522",
"row": "Boegen 22.5"
}
]
Schritt 2: LISP-Testrunner ausfuehren (BricsCAD)
Alle Tests auf einmal
(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp"))
SSG_RUN_ALL_TESTS
SSG_RUN_ALL_TESTS liest alltests.json und fuehrt fuer jedes Modul aus:
- Zeichnung leeren (ERASE ALL + PURGE x5)
test_<name>.lspladen undTEST_<NAME>ausfuehren- JSON-Export:
<name>:export-resultsaufrufen (immer) - Zeichnung speichern gemaess
save-Feld ("dxf","dwg"oder kein Speichern) - Bei Fehler: weiter mit naechstem Test (Fehlerisolation)
Einzeltest (z.B. nur Kreisel)
(load (strcat (getenv "DXFMAKRO") "/tests/test_kreisel.lsp"))
TEST_KREISEL
(kreisel:export-results (strcat (getenv "DXFMAKRO") "/tests/output"))
Ausgabe: results.json
[
{
"test_id": "KR_Kreuz_Q1_0Grad",
"status": "GEBAUT",
"block_name": "KREISEL_STANDARD",
"insert_point": [500.0, 500.0, 2500.0],
"rotation": 0.0,
"actual_kreiselart": "STANDARD",
"actual_hoehe": "2500"
}
]
Schritt 3: Python-Validierung (pytest)
bin\run_tests.bat --runall
Oder einzelnes Testmodul:
bin\run_tests.bat --runall test_kreisel.py
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: Merkmale, Datentypen, Vollstaendigkeit (ohne BricsCAD) |
TestOmnifloExportCSV |
CSV aus BricsCAD: Header, Spalten, JSON-Merkmale |
Tests, deren Eingabedaten fehlen (kein BricsCAD-Lauf), werden automatisch
uebersprungen (pytest.skip).
Schritt 4: Referenz-Management
# Aktuelle Ergebnisse als neue Referenz speichern
bin\run_tests.bat --set-as-reference
Kopiert alle Dateien aus output/ nach reference/. Nur bei bestandenen Tests verwenden.
Modulspezifische Testfaelle
Kreisel (kreisel_tests.json)
| Test-ID | Beschreibung | Params |
|---|---|---|
| KR_Kreuz_Q1_0Grad | Standard Kreisel, 0 Grad | rot=0, z=2500, abstand=2000 |
| KR_Kreuz_Q2_90Grad | Standard Kreisel, 90 Grad | rot=90, z=2500, abstand=3000 |
| KR_Kreuz_Q3_180Grad | Standard Kreisel, 180 Grad | rot=180, z=2500, abstand=4000 |
| KR_Kreuz_Q4_270Grad | Standard Kreisel, 270 Grad | rot=270, z=2500, abstand=5000 |
| KR_Schraeg_Q1_30Grad | Standard Kreisel, schraeg | rot=30, z=3000, abstand=3000 |
| KR_Pin_Q1_0Grad | Pin-Kreisel, 0 Grad | rot=0, typ=PIN, z=1500 |
| KR_Pin_Q1_90Grad | Pin-Kreisel, 90 Grad | rot=90, typ=PIN, z=1500 |
| KR_Pin_Q1_30Grad_Schraeg | Pin-Kreisel, schraeg | rot=30, typ=PIN, z=1500 |
Foerderer (foerderer_tests.json)
| Test-ID | Richtung | deltaL | deltaH |
|---|---|---|---|
| VF_Auf_0 | Auf | 7000 | 0 |
| VF_Auf_1000 | Auf | 7000 | 1000 |
| VF_Auf_2000 | Auf | 7000 | 2000 |
| VF_Auf_3000 | Auf | 7000 | 3000 |
| VF_Auf_4000 | Auf | 7000 | 4000 |
| VF_Auf_5000 | Auf | 7000 | 5000 |
| VF_Ab_0 | Ab | 7000 | 0 (GEOMETRISCH_UNMOEGLICH) |
| VF_Ab_1000 | Ab | 7000 | 1000 |
| VF_Ab_2000 | Ab | 7000 | 2000 |
| VF_Ab_3000 | Ab | 7000 | 3000 |
| VF_Ab_4000 | Ab | 7000 | 4000 |
| VF_Ab_5000 | Ab | 7000 | 5000 |
Omniflo (omniflo_tests.json)
Testfaelle basieren auf echten Sivas-Nummern (Boegen und Zusatzmodule).
Beispiele: 821104025, 821104025+0_B10090, 821104025+0_B10091, ...
Umgebungsvariablen
Werden via 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 |
Abhaengigkeiten
Python (tests/requirements.txt)
ezdxf>=1.0
pytest>=7.0
AutoLISP
- SSG_LIB muss geladen sein (Menue per
_MENULOADeingerichtet, siehe CLAUDE.md) test_run_all.lsplaedt die einzelnen Testrunner automatisch
Neuen Test erstellen
- Testdaten:
testdata/<modul>_tests.jsonerstellen (flaches JSON-Array) - LISP-Testrunner:
test_<modul>.lsperstellen mitc:TEST_<MODUL>und<modul>:export-results - Testregistry: Eintrag in
alltests.jsonhinzufuegen - Python-Validierung (optional):
test_<modul>.pyund Fixtures inconftest.py
Detailliertes Vorgehen und Codevorlagen: siehe tests/README.md.