forked from AG_QGIS/Plugin_SN_Basis
Auf Wrapper umgestellt, Prüfarchitektur QT6-kompatibel gemacht (Nicht lauffähig)
This commit is contained in:
@@ -1,11 +1,49 @@
|
||||
#run_tests.py
|
||||
import sys
|
||||
import os
|
||||
"""
|
||||
sn_basis/test/run_tests.py
|
||||
|
||||
Zentraler Test-Runner für sn_basis.
|
||||
Wrapper-konform, QGIS-unabhängig, CI- und IDE-fähig.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import datetime
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
|
||||
|
||||
# Minimaler Bootstrap, um sn_basis importierbar zu machen
|
||||
TEST_DIR = os.path.dirname(__file__)
|
||||
PLUGIN_ROOT = os.path.abspath(os.path.join(TEST_DIR, "..", ".."))
|
||||
|
||||
if PLUGIN_ROOT not in sys.path:
|
||||
sys.path.insert(0, PLUGIN_ROOT)
|
||||
|
||||
|
||||
from sn_basis.functions import syswrapper
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Bootstrap: Plugin-Root in sys.path eintragen
|
||||
# ---------------------------------------------------------
|
||||
|
||||
def bootstrap():
|
||||
"""
|
||||
Simuliert das QGIS-Plugin-Startverhalten:
|
||||
stellt sicher, dass sn_basis importierbar ist.
|
||||
"""
|
||||
plugin_root = syswrapper.get_plugin_root()
|
||||
syswrapper.add_to_sys_path(plugin_root)
|
||||
|
||||
|
||||
bootstrap()
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Farben
|
||||
# ---------------------------------------------------------
|
||||
|
||||
RED = "\033[91m"
|
||||
YELLOW = "\033[93m"
|
||||
GREEN = "\033[92m"
|
||||
@@ -13,36 +51,30 @@ CYAN = "\033[96m"
|
||||
MAGENTA = "\033[95m"
|
||||
RESET = "\033[0m"
|
||||
|
||||
# Globaler Testzähler
|
||||
GLOBAL_TEST_COUNTER = 0
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Eigene TestResult-Klasse (färbt Fehler/Skipped/OK)
|
||||
# Farbige TestResult-Klasse
|
||||
# ---------------------------------------------------------
|
||||
|
||||
class ColoredTestResult(unittest.TextTestResult):
|
||||
|
||||
def startTest(self, test):
|
||||
"""Vor jedem Test eine Nummer ausgeben."""
|
||||
global GLOBAL_TEST_COUNTER
|
||||
GLOBAL_TEST_COUNTER += 1
|
||||
self.stream.write(f"{CYAN}[Test {GLOBAL_TEST_COUNTER}]{RESET}\n")
|
||||
super().startTest(test)
|
||||
|
||||
def startTestRun(self):
|
||||
"""Wird einmal zu Beginn des gesamten Testlaufs ausgeführt."""
|
||||
super().startTestRun()
|
||||
|
||||
def startTestClass(self, test):
|
||||
"""Wird aufgerufen, wenn eine neue Testklasse beginnt."""
|
||||
cls = test.__class__
|
||||
file = inspect.getfile(cls)
|
||||
filename = os.path.basename(file)
|
||||
|
||||
self.stream.write(
|
||||
f"\n{MAGENTA}{'='*70}\n"
|
||||
f"\n{MAGENTA}{'=' * 70}\n"
|
||||
f"Starte Testklasse: {filename} → {cls.__name__}\n"
|
||||
f"{'='*70}{RESET}\n"
|
||||
f"{'=' * 70}{RESET}\n"
|
||||
)
|
||||
|
||||
def addError(self, test, err):
|
||||
@@ -57,31 +89,27 @@ class ColoredTestResult(unittest.TextTestResult):
|
||||
super().addSkip(test, reason)
|
||||
self.stream.write(f"{YELLOW}SKIPPED{RESET}: {reason}\n")
|
||||
|
||||
# unittest ruft diese Methode nicht automatisch auf → wir patchen es unten
|
||||
def addSuccess(self, test):
|
||||
super().addSuccess(test)
|
||||
self.stream.write(f"{GREEN}OK{RESET}\n")
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Eigener TestRunner, der unser ColoredTestResult nutzt
|
||||
# Farbiger TestRunner
|
||||
# ---------------------------------------------------------
|
||||
|
||||
class ColoredTestRunner(unittest.TextTestRunner):
|
||||
resultclass = ColoredTestResult
|
||||
|
||||
def _makeResult(self):
|
||||
result = super()._makeResult()
|
||||
|
||||
# Patch: unittest ruft startTestClass nicht automatisch auf
|
||||
original_start_test = result.startTest
|
||||
|
||||
def patched_start_test(test):
|
||||
# Wenn neue Klasse → Kopf ausgeben
|
||||
if not hasattr(result, "_last_test_class") or \
|
||||
result._last_test_class != test.__class__:
|
||||
result.startTestClass(test)
|
||||
result._last_test_class = test.__class__
|
||||
|
||||
original_start_test(test)
|
||||
|
||||
result.startTest = patched_start_test
|
||||
@@ -89,37 +117,30 @@ class ColoredTestRunner(unittest.TextTestRunner):
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Testlauf starten
|
||||
# Testlauf starten
|
||||
# ---------------------------------------------------------
|
||||
print("\n" + "="*70)
|
||||
print(f"{CYAN}Testlauf gestartet am: {datetime.datetime.now():%Y-%m-%d %H:%M:%S}{RESET}")
|
||||
print("="*70 + "\n")
|
||||
|
||||
# Projekt-Root dem Suchpfad hinzufügen
|
||||
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||
if project_root not in sys.path:
|
||||
sys.path.insert(0, project_root)
|
||||
|
||||
|
||||
def main():
|
||||
print("\n" + "=" * 70)
|
||||
print(
|
||||
f"{CYAN}Testlauf gestartet am: "
|
||||
f"{datetime.datetime.now():%Y-%m-%d %H:%M:%S}{RESET}"
|
||||
)
|
||||
print("=" * 70 + "\n")
|
||||
|
||||
loader = unittest.TestLoader()
|
||||
suite = unittest.TestSuite()
|
||||
|
||||
test_modules = [
|
||||
"test_dateipruefer",
|
||||
"test_stilpruefer",
|
||||
"test_linkpruefer",
|
||||
"test_qt_compat",
|
||||
"test_pruefmanager",
|
||||
]
|
||||
|
||||
for mod_name in test_modules:
|
||||
mod = __import__(mod_name)
|
||||
suite.addTests(loader.loadTestsFromModule(mod))
|
||||
suite = loader.discover(
|
||||
start_dir=os.path.dirname(__file__),
|
||||
pattern="test_*.py"
|
||||
)
|
||||
|
||||
runner = ColoredTestRunner(verbosity=2)
|
||||
runner.run(suite)
|
||||
result = runner.run(suite)
|
||||
|
||||
# Exit-Code für CI / Skripte
|
||||
return 0 if result.wasSuccessful() else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
raise SystemExit(main())
|
||||
|
||||
Reference in New Issue
Block a user