Test-Audit: Datei:Zeile und Quelltext-Ausgabe für bequemes Ansehen/Editieren
status zeigt je Treffer "<Datei>:<Zeile>" (in Editor-Terminals anklickbar) und optional per --code den Testquelltext im Terminal. Der Prüfstand selbst bleibt ohne Quelltext, um Diff-Lärm bei jeder Codeänderung zu vermeiden. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -132,6 +132,7 @@ als eigene Filter-Chips „Nie geprüft" / „Veraltet geprüft".
|
||||
```bash
|
||||
python scripts/test_audit.py status sn_verfahrensgebiet # Prüfstatus je Testfall anzeigen
|
||||
python scripts/test_audit.py status --nur ungeprueft # nur ungeprüfte Testfälle
|
||||
python scripts/test_audit.py status sn_basis --muster TestX --code # mit Quelltext im Terminal
|
||||
python scripts/test_audit.py markieren sn_basis TestX.test_y # als heute geprüft markieren
|
||||
```
|
||||
|
||||
@@ -139,6 +140,11 @@ python scripts/test_audit.py markieren sn_basis TestX.test_y # als heute gep
|
||||
Treffer, ohne zu schreiben — vor einem Muster mit vielen Treffern empfohlen. Das Skript importiert die
|
||||
Katalog-Logik aus `scripts/testkatalog.py`, statt sie zu duplizieren.
|
||||
|
||||
`status` zeigt zu jedem Treffer „<Datei>:<Zeile>" — in den meisten Editor-Terminals anklickbar, um den Test
|
||||
direkt zu öffnen und zu bearbeiten. Der Prüfstand selbst zeigt bewusst **keinen** Quelltext: er ist eine
|
||||
versionierte, generierte Datei, und Quelltext darin würde bei jeder Codeänderung riesige, wenig aussagekräftige
|
||||
Diffs erzeugen. Zum Lesen ohne Editor dient `--code`, zum Bearbeiten der übliche Weg über Konsole/Editor.
|
||||
|
||||
Abgrenzung zu Abschnitt 8 (Testkonzepte): Das Audit bestätigt, dass **vorhandene** Tests noch fachlich
|
||||
zutreffen. Ob überhaupt genug getestet wird, zeigen die Testkonzept-Seiten — das ist der nächste, gesonderte
|
||||
Schritt, kein Ersatz für das Audit.
|
||||
|
||||
+14
-2
@@ -11,11 +11,17 @@ sichtbar, welche Tests nie geprüft wurden oder sich seit der letzten Prüfung g
|
||||
Reine Standardbibliothek, kein Import von sn_basis/QGIS nötig, da nur mit ast geparst wird
|
||||
(genau wie testkatalog.py, dessen Funktionen hier wiederverwendet werden).
|
||||
|
||||
`status` zeigt je Treffer "<datei>:<zeile>" – in den meisten Terminals/Editoren (z. B. VS Code) anklickbar,
|
||||
um den Test direkt zum Bearbeiten zu öffnen. `--code` gibt zusätzlich den Testquelltext im Terminal aus, zum
|
||||
schnellen fachlichen Lesen ohne Editor. Bearbeitet wird die Testdatei ganz normal über die Konsole/den Editor –
|
||||
dieses Skript schreibt nur `docs/status/testpruefungen.json`, nie Testdateien.
|
||||
|
||||
Aufrufe (aus dem Workspace-Root):
|
||||
python scripts/test_audit.py status # alle Pakete
|
||||
python scripts/test_audit.py status sn_verfahrensgebiet # nur ein Paket
|
||||
python scripts/test_audit.py status sn_basis --nur ungeprueft # Filter auf Prüfstatus
|
||||
python scripts/test_audit.py status --muster grenzpunkt # Filter auf Bezeichner
|
||||
python scripts/test_audit.py status sn_basis --muster Test_x --code # mit Quelltext (zum Lesen, nicht editierbar)
|
||||
python scripts/test_audit.py markieren sn_basis TestHallo.test_x # als heute geprüft markieren
|
||||
python scripts/test_audit.py markieren sn_basis "TestX.*" --trocken # nur anzeigen, nichts schreiben
|
||||
python scripts/test_audit.py markieren sn_basis TestX.test_x --datum 2026-08-01 # Nacherfassung
|
||||
@@ -99,7 +105,12 @@ def befehl_status(args: argparse.Namespace) -> int:
|
||||
continue
|
||||
if gesucht_status and fall.pruefstatus != gesucht_status:
|
||||
continue
|
||||
print(f" {datei.anzeigepfad}::{fall.bezeichnung} -> {tk.pruef_text(fall)}")
|
||||
print(
|
||||
f" {datei.anzeigepfad}:{fall.zeile} {fall.bezeichnung} -> {tk.pruef_text(fall)}"
|
||||
)
|
||||
if args.code:
|
||||
for zeile in fall.quelltext.splitlines():
|
||||
print(f" {zeile}")
|
||||
return 0
|
||||
|
||||
|
||||
@@ -148,7 +159,7 @@ def befehl_markieren(args: argparse.Namespace) -> int:
|
||||
pruefungen, _ = tk.lies_pruefungen(args.pruefungsdatei)
|
||||
tk.setze_pruefstatus(katalog, pruefungen)
|
||||
for datei, fall in treffer:
|
||||
print(f"{datei.anzeigepfad}::{fall.bezeichnung} (vorher: {tk.pruef_text(fall)})")
|
||||
print(f"{datei.anzeigepfad}:{fall.zeile} {fall.bezeichnung} (vorher: {tk.pruef_text(fall)})")
|
||||
|
||||
if args.trocken:
|
||||
print(f"Trockenlauf – nichts geschrieben. {len(treffer)} Treffer.")
|
||||
@@ -170,6 +181,7 @@ def main() -> int:
|
||||
p_status.add_argument("pakete", nargs="*", help="Paketnamen (Standard: alle mit tests=true)")
|
||||
p_status.add_argument("--muster", help="nur Testfälle, deren Bezeichner diesen Text enthält (Teilstring)")
|
||||
p_status.add_argument("--nur", choices=sorted(NUR_ZU_PRUEFSTATUS), help="nur diesen Prüfstatus anzeigen")
|
||||
p_status.add_argument("--code", action="store_true", help="Quelltext jeder passenden Testmethode mit ausgeben")
|
||||
p_status.add_argument("--baseline-datei", type=Path, default=tk.BASELINE_DEFAULT)
|
||||
p_status.add_argument("--pruefungsdatei", type=Path, default=tk.PRUEFUNGEN_DEFAULT)
|
||||
p_status.set_defaults(func=befehl_status)
|
||||
|
||||
@@ -96,6 +96,8 @@ class Testfall:
|
||||
quellhash: str = ""
|
||||
pruefstatus: str = "nie geprüft"
|
||||
pruefdatum: str = ""
|
||||
zeile: int = 0
|
||||
quelltext: str = ""
|
||||
|
||||
@property
|
||||
def bezeichnung(self) -> str:
|
||||
@@ -262,6 +264,8 @@ def lies_testdatei(pfad: Path, paket: str) -> Testdatei:
|
||||
grund=grund or (klassen_grund if klassen_skip else ""),
|
||||
erwarteter_fehlschlag=erwartet or klassen_erwartet,
|
||||
quellhash=_funktionshash(zeilen, glied),
|
||||
zeile=glied.lineno,
|
||||
quelltext=_funktionsquelle(zeilen, glied),
|
||||
)
|
||||
)
|
||||
if gruppe.faelle:
|
||||
|
||||
@@ -176,7 +176,7 @@ class WorkspaceGestuetzteTests(unittest.TestCase):
|
||||
import argparse
|
||||
|
||||
args = argparse.Namespace(
|
||||
pakete=[], muster=None, nur=None,
|
||||
pakete=[], muster=None, nur=None, code=False,
|
||||
baseline_datei=self.root / "keine_baseline.json",
|
||||
pruefungsdatei=self.pruefungsdatei,
|
||||
)
|
||||
@@ -184,6 +184,20 @@ class WorkspaceGestuetzteTests(unittest.TestCase):
|
||||
self.assertEqual(code, 0)
|
||||
self.assertIn("test_eins", ausgabe)
|
||||
self.assertIn("nie geprüft", ausgabe)
|
||||
self.assertRegex(ausgabe, r"test_beispiel\.py:\d+")
|
||||
|
||||
def test_status_befehl_mit_code_gibt_quelltext_aus(self):
|
||||
"""Prüft, dass --code den Testquelltext der passenden Methode mit ausgibt."""
|
||||
import argparse
|
||||
|
||||
args = argparse.Namespace(
|
||||
pakete=[], muster="test_eins", nur=None, code=True,
|
||||
baseline_datei=self.root / "keine_baseline.json",
|
||||
pruefungsdatei=self.pruefungsdatei,
|
||||
)
|
||||
_, ausgabe = self._stdout(lambda: test_audit.befehl_status(args))
|
||||
self.assertIn("def test_eins(self):", ausgabe)
|
||||
self.assertIn("assertEqual(1, 1)", ausgabe)
|
||||
|
||||
def test_markieren_ohne_treffer_gibt_exitcode_1(self):
|
||||
"""Prüft, dass ein Muster ohne Treffer Exit-Code 1 liefert und keine Datei schreibt."""
|
||||
@@ -210,7 +224,7 @@ class WorkspaceGestuetzteTests(unittest.TestCase):
|
||||
self.assertTrue(self.pruefungsdatei.exists())
|
||||
|
||||
status_args = argparse.Namespace(
|
||||
pakete=[], muster="test_eins", nur=None,
|
||||
pakete=[], muster="test_eins", nur=None, code=False,
|
||||
baseline_datei=self.root / "keine_baseline.json",
|
||||
pruefungsdatei=self.pruefungsdatei,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user