# Testkonzept SSG_LIB - Hybrid AutoLISP + Python ## Uebersicht Die SSG_LIB AutoLISP-Makros werden ueber einen zweistufigen Hybrid-Ansatz getestet: 1. **AutoLISP** (in BricsCAD): Liest JSON-Testfaelle, fuehrt die Funktionen aus, schreibt Ergebnisse als JSON und DXF. 2. **Python** (pytest + ezdxf): Validiert die Ergebnisse automatisch gegen erwartete Werte und optionale Referenz-DXFs. ``` Python (pytest) AutoLISP (BricsCAD) Python (pytest) =============== ==================== =============== Testfall-Definitionen --> Ausfuehrung der --> Validierung: als JSON bereitstellen LISP-Funktionen - JSON-Ergebnisse + DXF + results.json - DXF-Geometrie - Referenz-Vergleich ``` ## Verzeichnisstruktur ``` tests/ ├── testdata/ # JSON-Testfall-Definitionen (versioniert) │ ├── kreisel_tests.json │ ├── vario_tests.json │ └── omniflo_tests.json ├── reference/ # Abgenommene Referenz-DXFs (versioniert) │ └── kreisel_ref.dxf ├── output/ # Generierte Ergebnisse (in .gitignore) │ ├── kreisel_tests.dxf │ └── kreisel_results.json ├── ssg_testrunner.lsp # LISP Test-Runner ├── conftest.py # pytest Fixtures ├── test_kreisel.py # pytest Kreisel-Validierung ├── test_vario.py # pytest Vario-Validierung ├── test_omniflo.py # pytest Omniflo-Validierung └── requirements.txt # Python-Abhaengigkeiten (ezdxf, pytest) ``` ## Schritt 1: Testfaelle definieren (JSON) Jedes Modul hat eine eigene JSON-Datei in `tests/testdata/`. Aufbau: ```json { "module": "Kreisel", "version": "1.0", "description": "ILS Kreisel Testfaelle", "tests": [ { "id": "KR_Horiz_ObenUnten", "function": "draw-module", "params": { "basepoint": [500.0, 5000.0, 2500.0], "abstand": 4200.0, "rotation": 270.0, "attribs": { "KREISELART": "STANDARD", "NAME": "TEST_H_ObenUnten" } }, "expect": { "attributes": { "KREISELART": "STANDARD", "DREHUNG": "270", "ABSTAND": "4200" }, "block_prefix": "KR_", "min_entities": 6 } } ] } ``` ### Felder | Feld | Beschreibung | |---|---| | `id` | Eindeutiger Testfall-Name | | `function` | Aufzurufende LISP-Funktion | | `params` | Uebergabewerte an die Funktion | | `expect.attributes` | Erwartete Block-Attribute nach Ausfuehrung | | `expect.block_prefix` | Erwartetes Praefix des erzeugten Block-Namens | | `expect.min_entities` | Mindestanzahl Entities im erzeugten Block | ## Schritt 2: LISP Test-Runner (ssg_testrunner.lsp) Der LISP Test-Runner liest die JSON-Testfaelle, fuehrt die Funktionen in BricsCAD aus und schreibt die Ergebnisse. ### Aufruf in BricsCAD ``` Command: TESTRUN "kreisel" ``` Der Befehl: 1. Liest `tests/testdata/kreisel_tests.json` 2. Erstellt eine neue leere Zeichnung 3. Fuehrt fuer jeden Testfall die angegebene Funktion mit den Parametern aus 4. Sammelt Ergebnisse: Block-Handle, tatsaechliche Attribute, Insertionspunkt 5. Schreibt `tests/output/kreisel_results.json` 6. Speichert die Zeichnung als `tests/output/kreisel_tests.dxf` ### Ausgabe: results.json ```json [ { "test_id": "KR_Horiz_ObenUnten", "status": "executed", "block_handle": "A3F", "block_name": "KR_STANDARD_01", "insert_point": [500.0, 5000.0, 2500.0], "rotation": 270.0, "actual_attributes": { "KREISELART": "STANDARD", "DREHUNG": "270", "ABSTAND": "4200", "NAME": "TEST_H_ObenUnten" } } ] ``` ## Schritt 3: Python-Validierung (pytest) Die Python-Tests lesen `results.json` und die erzeugte DXF-Datei und pruefen: ### 3a. Attribut-Pruefung (results.json) Vergleicht `actual_attributes` aus results.json gegen `expect.attributes` aus den Testdefinitionen. Keine BricsCAD-Instanz noetig. ### 3b. Geometrie-Pruefung (ezdxf) Oeffnet die erzeugte DXF-Datei mit der Python-Bibliothek `ezdxf` und prueft: - **Block-Existenz**: Alle erwarteten Bloecke im Modelspace vorhanden - **Entity-Anzahl**: Mindestanzahl Entities pro Block - **Kreisradien**: AN8/SP8-Kreise haben korrekten Radius (400mm) - **Linienlaengen**: Tangenten haben korrekte Laenge (= Abstand) - **Layer-Zuordnung**: Entities auf korrektem Layer - **Insertionspunkte**: Bloecke an erwarteter Position ### 3c. Referenz-Vergleich Vergleicht die Ergebnis-DXF gegen eine abgenommene Referenz-DXF: - Gleiche Anzahl Bloecke im Modelspace - Gleiche Block-Typen - Gleiche Attributwerte ## Schritt 4: Referenz-Management ### Neue Referenz erstellen (erster Lauf oder nach Aenderung) ```bash # 1. Tests in BricsCAD ausfuehren # Command: TESTRUN "kreisel" # 2. Ergebnis-DXF visuell pruefen (in BricsCAD oeffnen) # 3. Wenn OK: Als neue Referenz speichern copy tests\output\kreisel_tests.dxf tests\reference\kreisel_ref.dxf ``` ### Referenz aktualisieren Wenn sich die LISP-Logik aendert und die neuen Ergebnisse korrekt sind: ```bash # 1. Tests in BricsCAD ausfuehren # 2. Ergebnis visuell pruefen # 3. Python-Tests zeigen Referenz-Abweichung: pytest tests/test_kreisel.py -v # FAILED test_block_count_matches_reference - 6 != 5 # 4. Neue Referenz speichern copy tests\output\kreisel_tests.dxf tests\reference\kreisel_ref.dxf # 5. Tests erneut ausfuehren - jetzt PASS pytest tests/test_kreisel.py -v ``` ## Ausfuehrung ### Kompletter Testlauf ```bash # Umgebung setzen bin\setenv.bat # 1. Testdaten-DXF erzeugen (Python, optional wenn Basis-DXF benoetigt) python tests/create_testbase.py # 2. BricsCAD starten und Tests ausfuehren # In BricsCAD: TESTRUN "kreisel" # In BricsCAD: TESTRUN "vario" # In BricsCAD: TESTRUN "omniflo" # 3. Python-Validierung pytest tests/ -v ``` ### Nur Python-Validierung (ohne BricsCAD) ```bash # Setzt voraus, dass output/ bereits erzeugt wurde pytest tests/ -v ``` ### Einzelnes Modul testen ```bash pytest tests/test_kreisel.py -v ``` ## Umgebungsvariablen | Variable | Pfad | Beschreibung | |---|---|---| | `DXFM_TESTS` | `/tests` | Test-Wurzelverzeichnis | | `DXFM_TESTDATA` | `/tests/testdata` | JSON-Testdefinitionen | | `DXFM_TESTOUT` | `/tests/output` | Generierte Ergebnisse | | `DXFM_TESTREF` | `/tests/reference` | Abgenommene Referenzen | ## Abhaengigkeiten ### Python (tests/requirements.txt) ``` ezdxf>=1.0 pytest>=7.0 ``` ### AutoLISP - SSG_LIB muss geladen sein (ssg_load.lsp) - `ssg_testrunner.lsp` wird manuell oder via on_start geladen ## Modulspezifische Testfaelle ### Kreisel (kreisel_tests.json) | Test-ID | Beschreibung | Params | |---|---|---| | KR_Horiz_ObenUnten | Horizontaler Kreisel, oben nach unten | rot=270, art=STANDARD | | KR_Horiz_UntenOben | Horizontaler Kreisel, unten nach oben | rot=90, art=PIN | | KR_Vert_LinksRechts | Vertikaler Kreisel, links nach rechts | rot=0, art=PIN | | KR_Vert_RechtsLinks | Vertikaler Kreisel, rechts nach links | rot=180, art=STANDARD | | KR_Insert_Schraeg | Kreisel mit 10 Grad Drehung | rot=10, abstand=6000 | ### Vario (vario_tests.json) | Test-ID | Beschreibung | Params | |---|---|---| | VF_Gerade_1Segment | Einzelnes gerades Segment | laenge=2000 | | VF_Gerade_3Segmente | Drei gerade Segmente | laenge=6000 | | VF_Gefaelle_Standard | Gefaellestrecke Standard | hoehe=500 | | VF_Bogen_Links | Linksbogen | winkel=90 | | VF_Bogen_Rechts | Rechtsbogen | winkel=-90 | ### Omniflo (omniflo_tests.json) | Test-ID | Beschreibung | Params | |---|---|---| | OM_Bogen_90 | 90-Grad Bogen | winkel=90 | | OM_Weiche_Links | Linksweiche | seite=L | | OM_Weiche_Rechts | Rechtsweiche | seite=R |