15 KiB
Tests - SSG_LIB Testarchitektur
Uebersicht
Die Tests folgen einer zweistufigen Architektur:
- LISP-Testrunner (
.lsp) — laufen in BricsCAD, erzeugen Ergebnisdateien - Python-Validierung (
.py) — pruefen die Ergebnisse mit pytest + ezdxf
tests/alltests.json
|
v
BricsCAD Kommandozeile
| |
| SSG_RUN_ALL_TESTS |
| (TEST_KREISEL, |
| TEST_FOERDERER, |
| TEST_OMNIFLO, |
| TEST_GEFAELLESTRECKE) |
| | |
v v |
tests/output/ |
kreisel_results.json (immer) |
kreisel_tests.dxf (save: dxf) |
foerderer_results.json (immer) |
foerderer_tests.dwg (save: dwg) |
omniflo_results.json (immer) |
omniflo_tests.dxf (save: dxf) |
gefaellestrecke_results.json |
gefaellestrecke_tests.dwg |
|
bin\run_tests.bat --runall
|
pytest -v
|
test_kreisel.py
test_omniflo.py
test_foerderer.py
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 _Extentsauf 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:EXPORTSIVASlaufen nicht automatisch mit — CSV/Sivas- Export danach bei Bedarf manuell ueberTEST_EXPORT_ALL(tests/test_export_all.lsp, Menuepunkt "Export CSV/Sivas ALL"), das alle vorhandenen DXF/DWG-Dateien austests/output/einliest und je Datei<basis>_export.csv/<basis>_sivas.csverzeugt. - Automatik-Modus (Ja): Zeichnung wird gespeichert, direkt per
c:EXPORTCSV/c:EXPORTSIVASexportiert (<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.
[
{ "name": "kreisel", "save": "dxf" },
{ "name": "foerderer", "save": "dwg" },
{ "name": "omniflo", "save": "dxf" },
{ "name": "gefaellestrecke", "save": "dwg" }
]
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 |
JSON-Export laeuft immer — unabhaengig vom save-Feld. Die Datei <name>_results.json
wird in tests/output/ geschrieben, sobald der Test abgeschlossen ist.
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 sollnull(oder Feld weglassen) — wenn nur der JSON-Export benoetigt wird
Ablauf fuer den Anwender
-
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 nachtests/output/. -
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.
-
Kommandozeile: Ergebnisse validieren oder als neue Referenz speichern:
bin\run_tests.bat --runall— pytest prueft die Ergebnisse ausoutput/gegen Testdefinitionen und Referenzdatenbin\run_tests.bat --set-as-reference— nach erfolgreicher Pruefung die aktuellen Ergebnisse als neue Referenz uebernehmen (kopiertoutput/nachreference/)
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_export_all.lsp # LISP-Testrunner: C:TEST_EXPORT_ALL (manuell, nicht in alltests.json)
testdata/
kreisel_tests.json # Testfall-Definitionen fuer Kreisel
omniflo_tests.json # Testfall-Definitionen fuer Omniflo
output/ # Ergebnisse aus BricsCAD (nicht in Git)
kreisel_results.json # JSON-Ergebnisse pro Testmodul
kreisel_tests.dxf # DXF-Zeichnung pro Testmodul
foerderer_results.json
foerderer_tests.dwg
omniflo_results.json
omniflo_tests.dxf
gefaellestrecke_results.json
gefaellestrecke_tests.dwg
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)
kreisel_ref.dxf
...
Workflow
1. LISP-Tests in BricsCAD ausfuehren
BricsCAD starten (ueber bin\start_briscad.bat) und Module laden:
(load (strcat (getenv "DXFMAKRO") "/Lisp/ssg_load.lsp"))
Dann alle Tests auf einmal ausfuehren:
;; 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:
- Zeichnung leeren (ERASE ALL + PURGE x5) — saubere Basis fuer jeden Test
test_<name>.lspladen undTEST_<NAME>ausfuehren- JSON-Export aufrufen:
<name>:export-results— immer, unabhaengig vonsave - Zeichnung speichern — nur wenn
"save"inalltests.jsongesetzt ist ("dxf"oder"dwg") - Bei Fehler: weiter mit naechstem Test (
vl-catch-all-apply)
Einzeltest (z.B. nur Kreisel pruefen):
;; 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
bin\run_tests.bat --runall
Oder fuer ein einzelnes Testmodul:
bin\run_tests.bat --runall 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 Testlauf die Ergebnisse als Referenz speichern:
bin\run_tests.bat --set-as-reference
Kopiert alle Dateien aus output/ nach reference/. Nur bei bestandenen Tests verwenden.
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):
[
{
"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 Testfallsfunction—"insert"oder"connect"- Eingabeparameter (
x,y,z,abstand,rotation,typfuer Insert;start_x/y/z,end_x/y/z,typfuer Connect) expect_*— Erwartete Ergebniswerte (fuer Python-Validierung)
Omniflo-Beispiel (omniflo_tests.json):
[
{
"sivasnr": "834372001",
"type": "bogen",
"description": "Bogen 90 Grad R200",
"hoehe": 2000,
"drehung": 0
}
]
Schritt 2: LISP-Testrunner erweitern (falls neues Modul)
Fuer ein neues Modul eine neue .lsp-Datei erstellen nach dem Muster:
;; 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:
{ "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 |
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-jsonerwartet ein flaches JSON-Array mit flachen Objekten (kein Nesting)omni:valliest 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:
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:
@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():
path = os.path.join(_reference_dir(), "<modul>_ref.dxf")
if not os.path.exists(path):
pytest.skip("Referenz nicht vorhanden")
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 |
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 |