forked from AG_QGIS/Plugin_SN_Basis
Anpassung an den Wrappern für sn_plan41
This commit is contained in:
1
tests/__init__.py
Normal file
1
tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
#Testordner
|
||||
154
tests/run_tests.py
Normal file
154
tests/run_tests.py
Normal file
@@ -0,0 +1,154 @@
|
||||
"""
|
||||
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
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Pre-Bootstrap: Plugin-Root in sys.path eintragen
|
||||
# ---------------------------------------------------------
|
||||
|
||||
THIS_FILE = Path(__file__).resolve()
|
||||
PLUGIN_ROOT = THIS_FILE.parents[2]
|
||||
|
||||
if str(PLUGIN_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(PLUGIN_ROOT))
|
||||
|
||||
from sn_basis.functions import (
|
||||
get_plugin_root,
|
||||
add_to_sys_path,
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Bootstrap: Plugin-Root in sys.path eintragen
|
||||
# ---------------------------------------------------------
|
||||
|
||||
def bootstrap():
|
||||
"""
|
||||
Simuliert das QGIS-Plugin-Startverhalten:
|
||||
stellt sicher, dass sn_basis importierbar ist.
|
||||
"""
|
||||
plugin_root = get_plugin_root()
|
||||
add_to_sys_path(plugin_root)
|
||||
|
||||
|
||||
bootstrap()
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Farben
|
||||
# ---------------------------------------------------------
|
||||
|
||||
RED = "\033[91m"
|
||||
YELLOW = "\033[93m"
|
||||
GREEN = "\033[92m"
|
||||
CYAN = "\033[96m"
|
||||
MAGENTA = "\033[95m"
|
||||
RESET = "\033[0m"
|
||||
|
||||
GLOBAL_TEST_COUNTER = 0
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Farbige TestResult-Klasse
|
||||
# ---------------------------------------------------------
|
||||
|
||||
class ColoredTestResult(unittest.TextTestResult):
|
||||
|
||||
_last_test_class: type | None = None
|
||||
|
||||
|
||||
def startTest(self, test):
|
||||
global GLOBAL_TEST_COUNTER
|
||||
GLOBAL_TEST_COUNTER += 1
|
||||
self.stream.write(f"{CYAN}[Test {GLOBAL_TEST_COUNTER}]{RESET}\n")
|
||||
super().startTest(test)
|
||||
|
||||
def startTestClass(self, test):
|
||||
cls = test.__class__
|
||||
file = inspect.getfile(cls)
|
||||
filename = os.path.basename(file)
|
||||
|
||||
self.stream.write(
|
||||
f"\n{MAGENTA}{'=' * 70}\n"
|
||||
f"Starte Testklasse: {filename} → {cls.__name__}\n"
|
||||
f"{'=' * 70}{RESET}\n"
|
||||
)
|
||||
|
||||
def addError(self, test, err):
|
||||
super().addError(test, err)
|
||||
self.stream.write(f"{RED}ERROR{RESET}\n")
|
||||
|
||||
def addFailure(self, test, err):
|
||||
super().addFailure(test, err)
|
||||
self.stream.write(f"{RED}FAILURE{RESET}\n")
|
||||
|
||||
def addSkip(self, test, reason):
|
||||
super().addSkip(test, reason)
|
||||
self.stream.write(f"{YELLOW}SKIPPED{RESET}: {reason}\n")
|
||||
|
||||
def addSuccess(self, test):
|
||||
super().addSuccess(test)
|
||||
self.stream.write(f"{GREEN}OK{RESET}\n")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Farbiger TestRunner
|
||||
# ---------------------------------------------------------
|
||||
|
||||
class ColoredTestRunner(unittest.TextTestRunner):
|
||||
|
||||
def _makeResult(self):
|
||||
result = ColoredTestResult(
|
||||
self.stream,
|
||||
self.descriptions,
|
||||
self.verbosity,
|
||||
)
|
||||
|
||||
original_start_test = result.startTest
|
||||
|
||||
def patched_start_test(test):
|
||||
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
|
||||
return result
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Testlauf starten
|
||||
# ---------------------------------------------------------
|
||||
|
||||
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 = loader.discover(
|
||||
start_dir=os.path.dirname(__file__),
|
||||
pattern="test_*.py"
|
||||
)
|
||||
|
||||
runner = ColoredTestRunner(verbosity=2)
|
||||
result = runner.run(suite)
|
||||
|
||||
# Exit-Code für CI / Skripte
|
||||
return 0 if result.wasSuccessful() else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
9
tests/start_osgeo4w_qgis.bat
Normal file
9
tests/start_osgeo4w_qgis.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
SET OSGEO4W_ROOT=D:\QGISQT5
|
||||
call %OSGEO4W_ROOT%\bin\o4w_env.bat
|
||||
set QGIS_PREFIX_PATH=%OSGEO4W_ROOT%\apps\qgis
|
||||
set PYTHONPATH=%QGIS_PREFIX_PATH%\python;%PYTHONPATH%
|
||||
set PATH=%OSGEO4W_ROOT%\bin;%QGIS_PREFIX_PATH%\bin;%PATH%
|
||||
|
||||
REM Neue Eingabeaufforderung starten und Python-Skript ausführen
|
||||
start cmd /k "python run_tests.py"
|
||||
2
tests/test_bootstrap.py
Normal file
2
tests/test_bootstrap.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from sn_basis.functions import sys_wrapper
|
||||
sys_wrapper.add_to_sys_path(sys_wrapper.get_plugin_root())
|
||||
104
tests/test_dateipruefer.py
Normal file
104
tests/test_dateipruefer.py
Normal file
@@ -0,0 +1,104 @@
|
||||
# sn_basis/test/test_dateipruefer.py
|
||||
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from sn_basis.modules.Dateipruefer import Dateipruefer
|
||||
|
||||
|
||||
class TestDateipruefer(unittest.TestCase):
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 1. Leere Eingabe erlaubt
|
||||
# -----------------------------------------------------
|
||||
def test_leereingabe_erlaubt(self):
|
||||
pruefer = Dateipruefer(
|
||||
pfad="",
|
||||
leereingabe_erlaubt=True
|
||||
)
|
||||
|
||||
result = pruefer.pruefe()
|
||||
|
||||
self.assertFalse(result.ok)
|
||||
self.assertEqual(result.aktion, "leereingabe_erlaubt")
|
||||
self.assertIsNone(result.kontext)
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 2. Leere Eingabe nicht erlaubt
|
||||
# -----------------------------------------------------
|
||||
def test_leereingabe_nicht_erlaubt(self):
|
||||
pruefer = Dateipruefer(
|
||||
pfad="",
|
||||
leereingabe_erlaubt=False
|
||||
)
|
||||
|
||||
result = pruefer.pruefe()
|
||||
|
||||
self.assertFalse(result.ok)
|
||||
self.assertEqual(result.aktion, "leereingabe_nicht_erlaubt")
|
||||
self.assertIsNone(result.kontext)
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 3. Standarddatei vorschlagen
|
||||
# -----------------------------------------------------
|
||||
def test_standarddatei_vorschlagen(self):
|
||||
pruefer = Dateipruefer(
|
||||
pfad="",
|
||||
standarddatei="/tmp/std.txt"
|
||||
)
|
||||
|
||||
result = pruefer.pruefe()
|
||||
|
||||
self.assertFalse(result.ok)
|
||||
self.assertEqual(result.aktion, "standarddatei_vorschlagen")
|
||||
self.assertEqual(result.kontext, Path("/tmp/std.txt"))
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 4. Temporäre Datei erlaubt
|
||||
# -----------------------------------------------------
|
||||
def test_temporaer_erlaubt(self):
|
||||
pruefer = Dateipruefer(
|
||||
pfad="",
|
||||
temporaer_erlaubt=True
|
||||
)
|
||||
|
||||
result = pruefer.pruefe()
|
||||
|
||||
self.assertFalse(result.ok)
|
||||
self.assertEqual(result.aktion, "temporaer_erlaubt")
|
||||
self.assertIsNone(result.kontext)
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 5. Datei existiert nicht
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.Dateipruefer.file_exists", return_value=False)
|
||||
def test_datei_nicht_gefunden(self, mock_exists):
|
||||
pruefer = Dateipruefer(
|
||||
pfad="/tmp/nichtvorhanden.txt"
|
||||
)
|
||||
|
||||
result = pruefer.pruefe()
|
||||
|
||||
self.assertFalse(result.ok)
|
||||
self.assertEqual(result.aktion, "datei_nicht_gefunden")
|
||||
self.assertEqual(result.kontext, Path("/tmp/nichtvorhanden.txt"))
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 6. Datei existiert
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.Dateipruefer.file_exists", return_value=True)
|
||||
def test_datei_ok(self, mock_exists):
|
||||
pruefer = Dateipruefer(
|
||||
pfad="/tmp/test.txt"
|
||||
)
|
||||
|
||||
result = pruefer.pruefe()
|
||||
|
||||
self.assertTrue(result.ok)
|
||||
self.assertEqual(result.aktion, "ok")
|
||||
self.assertEqual(result.kontext, Path("/tmp/test.txt"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
171
tests/test_layerpruefer.py
Normal file
171
tests/test_layerpruefer.py
Normal file
@@ -0,0 +1,171 @@
|
||||
# sn_basis/test/test_layerpruefer.py
|
||||
|
||||
import unittest
|
||||
|
||||
from sn_basis.modules.layerpruefer import Layerpruefer
|
||||
from sn_basis.modules.pruef_ergebnis import pruef_ergebnis
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Mock-Layer für Wrapper-Tests
|
||||
# ---------------------------------------------------------
|
||||
class MockLayer:
|
||||
def __init__(
|
||||
self,
|
||||
exists=True,
|
||||
visible=True,
|
||||
layer_type="vector",
|
||||
geometry_type="Polygon",
|
||||
feature_count=10,
|
||||
crs="EPSG:25833",
|
||||
fields=None,
|
||||
source="/tmp/test.shp",
|
||||
editable=True,
|
||||
):
|
||||
self.exists = exists
|
||||
self.visible = visible
|
||||
self.layer_type = layer_type
|
||||
self.geometry_type = geometry_type
|
||||
self.feature_count = feature_count
|
||||
self.crs = crs
|
||||
self.fields = fields or []
|
||||
self.source = source
|
||||
self.editable = editable
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Wrapper-Mocks (monkeypatching)
|
||||
# ---------------------------------------------------------
|
||||
def mock_layer_exists(layer):
|
||||
return layer is not None and layer.exists
|
||||
|
||||
|
||||
def mock_is_layer_visible(layer):
|
||||
return layer.visible
|
||||
|
||||
|
||||
def mock_get_layer_type(layer):
|
||||
return layer.layer_type
|
||||
|
||||
|
||||
def mock_get_layer_geometry_type(layer):
|
||||
return layer.geometry_type
|
||||
|
||||
|
||||
def mock_get_layer_feature_count(layer):
|
||||
return layer.feature_count
|
||||
|
||||
|
||||
def mock_get_layer_crs(layer):
|
||||
return layer.crs
|
||||
|
||||
|
||||
def mock_get_layer_fields(layer):
|
||||
return layer.fields
|
||||
|
||||
|
||||
def mock_get_layer_source(layer):
|
||||
return layer.source
|
||||
|
||||
|
||||
def mock_is_layer_editable(layer):
|
||||
return layer.editable
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Testklasse
|
||||
# ---------------------------------------------------------
|
||||
class TestLayerpruefer(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
# Monkeypatching der im Layerpruefer verwendeten Wrapper-Funktionen
|
||||
import sn_basis.modules.layerpruefer as module
|
||||
|
||||
module.layer_exists = mock_layer_exists
|
||||
module.is_layer_visible = mock_is_layer_visible
|
||||
module.get_layer_type = mock_get_layer_type
|
||||
module.get_layer_geometry_type = mock_get_layer_geometry_type
|
||||
module.get_layer_feature_count = mock_get_layer_feature_count
|
||||
module.get_layer_crs = mock_get_layer_crs
|
||||
module.get_layer_fields = mock_get_layer_fields
|
||||
module.get_layer_source = mock_get_layer_source
|
||||
module.is_layer_editable = mock_is_layer_editable
|
||||
|
||||
|
||||
# -----------------------------------------------------
|
||||
# Tests
|
||||
# -----------------------------------------------------
|
||||
|
||||
def test_layer_exists(self):
|
||||
layer = MockLayer(exists=False)
|
||||
pruefer = Layerpruefer(layer)
|
||||
ergebnis = pruefer.pruefe()
|
||||
self.assertFalse(ergebnis.ok)
|
||||
self.assertEqual(ergebnis.aktion, "layer_nicht_gefunden")
|
||||
|
||||
def test_layer_unsichtbar(self):
|
||||
layer = MockLayer(visible=False)
|
||||
pruefer = Layerpruefer(layer, muss_sichtbar_sein=True)
|
||||
ergebnis = pruefer.pruefe()
|
||||
self.assertFalse(ergebnis.ok)
|
||||
self.assertEqual(ergebnis.aktion, "layer_unsichtbar")
|
||||
|
||||
def test_falscher_layertyp(self):
|
||||
layer = MockLayer(layer_type="raster")
|
||||
pruefer = Layerpruefer(layer, erwarteter_layertyp="vector")
|
||||
ergebnis = pruefer.pruefe()
|
||||
self.assertFalse(ergebnis.ok)
|
||||
self.assertEqual(ergebnis.aktion, "falscher_layertyp")
|
||||
|
||||
def test_falscher_geotyp(self):
|
||||
layer = MockLayer(geometry_type="Point")
|
||||
pruefer = Layerpruefer(layer, erwarteter_geotyp="Polygon")
|
||||
ergebnis = pruefer.pruefe()
|
||||
self.assertFalse(ergebnis.ok)
|
||||
self.assertEqual(ergebnis.aktion, "falscher_geotyp")
|
||||
|
||||
def test_layer_leer(self):
|
||||
layer = MockLayer(feature_count=0)
|
||||
pruefer = Layerpruefer(layer)
|
||||
ergebnis = pruefer.pruefe()
|
||||
self.assertFalse(ergebnis.ok)
|
||||
self.assertEqual(ergebnis.aktion, "layer_leer")
|
||||
|
||||
def test_falsches_crs(self):
|
||||
layer = MockLayer(crs="EPSG:4326")
|
||||
pruefer = Layerpruefer(layer, erwartetes_crs="EPSG:25833")
|
||||
ergebnis = pruefer.pruefe()
|
||||
self.assertFalse(ergebnis.ok)
|
||||
self.assertEqual(ergebnis.aktion, "falsches_crs")
|
||||
|
||||
def test_felder_fehlen(self):
|
||||
layer = MockLayer(fields=["id"])
|
||||
pruefer = Layerpruefer(layer, erforderliche_felder=["id", "name"])
|
||||
ergebnis = pruefer.pruefe()
|
||||
self.assertFalse(ergebnis.ok)
|
||||
self.assertEqual(ergebnis.aktion, "felder_fehlen")
|
||||
|
||||
def test_datenquelle_unerwartet(self):
|
||||
layer = MockLayer(source="/tmp/test.shp")
|
||||
pruefer = Layerpruefer(layer, erlaubte_datenquellen=["/tmp/allowed.shp"])
|
||||
ergebnis = pruefer.pruefe()
|
||||
self.assertFalse(ergebnis.ok)
|
||||
self.assertEqual(ergebnis.aktion, "datenquelle_unerwartet")
|
||||
|
||||
def test_layer_nicht_editierbar(self):
|
||||
layer = MockLayer(editable=False)
|
||||
pruefer = Layerpruefer(layer, muss_editierbar_sein=True)
|
||||
ergebnis = pruefer.pruefe()
|
||||
self.assertFalse(ergebnis.ok)
|
||||
self.assertEqual(ergebnis.aktion, "layer_nicht_editierbar")
|
||||
|
||||
def test_layer_ok(self):
|
||||
layer = MockLayer()
|
||||
pruefer = Layerpruefer(layer)
|
||||
ergebnis = pruefer.pruefe()
|
||||
self.assertTrue(ergebnis.ok)
|
||||
self.assertEqual(ergebnis.aktion, "ok")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
79
tests/test_linkpruefer.py
Normal file
79
tests/test_linkpruefer.py
Normal file
@@ -0,0 +1,79 @@
|
||||
# sn_basis/test/test_linkpruefer.py
|
||||
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from sn_basis.modules.linkpruefer import Linkpruefer
|
||||
from sn_basis.functions.qgiscore_wrapper import NetworkReply
|
||||
|
||||
|
||||
class TestLinkpruefer(unittest.TestCase):
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 1. Remote-Link erreichbar
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.linkpruefer.network_head")
|
||||
def test_remote_link_ok(self, mock_head):
|
||||
mock_head.return_value = NetworkReply(error=0)
|
||||
|
||||
lp = Linkpruefer()
|
||||
result = lp.pruefe("http://example.com")
|
||||
|
||||
self.assertTrue(result.ok)
|
||||
self.assertEqual(result.aktion, "ok")
|
||||
self.assertEqual(result.kontext, "http://example.com")
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 2. Remote-Link nicht erreichbar
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.linkpruefer.network_head")
|
||||
def test_remote_link_error(self, mock_head):
|
||||
mock_head.return_value = NetworkReply(error=1)
|
||||
|
||||
lp = Linkpruefer()
|
||||
result = lp.pruefe("http://example.com")
|
||||
|
||||
self.assertFalse(result.ok)
|
||||
self.assertEqual(result.aktion, "url_nicht_erreichbar")
|
||||
self.assertEqual(result.kontext, "http://example.com")
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 3. Netzwerkfehler (None)
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.linkpruefer.network_head", return_value=None)
|
||||
def test_remote_link_network_error(self, mock_head):
|
||||
lp = Linkpruefer()
|
||||
result = lp.pruefe("http://example.com")
|
||||
|
||||
self.assertFalse(result.ok)
|
||||
self.assertEqual(result.aktion, "netzwerkfehler")
|
||||
self.assertEqual(result.kontext, "http://example.com")
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 4. Lokaler Pfad existiert nicht
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.linkpruefer.file_exists", return_value=False)
|
||||
def test_local_link_not_found(self, mock_exists):
|
||||
lp = Linkpruefer()
|
||||
result = lp.pruefe("/path/to/missing/file.shp")
|
||||
|
||||
self.assertFalse(result.ok)
|
||||
self.assertEqual(result.aktion, "pfad_nicht_gefunden")
|
||||
self.assertEqual(result.kontext, Path("/path/to/missing/file.shp"))
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 5. Lokaler Pfad existiert
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.linkpruefer.file_exists", return_value=True)
|
||||
def test_local_link_ok(self, mock_exists):
|
||||
lp = Linkpruefer()
|
||||
result = lp.pruefe("/path/to/file.shp")
|
||||
|
||||
self.assertTrue(result.ok)
|
||||
self.assertEqual(result.aktion, "ok")
|
||||
self.assertEqual(result.kontext, Path("/path/to/file.shp"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
146
tests/test_pruefmanager.py
Normal file
146
tests/test_pruefmanager.py
Normal file
@@ -0,0 +1,146 @@
|
||||
# sn_basis/test/test_pruefmanager.py
|
||||
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from sn_basis.modules.Pruefmanager import Pruefmanager
|
||||
from sn_basis.modules.pruef_ergebnis import pruef_ergebnis
|
||||
|
||||
|
||||
class TestPruefmanager(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.manager = Pruefmanager()
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 1. OK-Ergebnis → keine Interaktion
|
||||
# -----------------------------------------------------
|
||||
def test_ok(self):
|
||||
ergebnis = pruef_ergebnis(True, "Alles gut", "ok", None)
|
||||
entscheidung = self.manager.verarbeite(ergebnis)
|
||||
|
||||
self.assertTrue(entscheidung.ok)
|
||||
self.assertEqual(entscheidung.aktion, "ok")
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 2. Leere Eingabe erlaubt → Nutzer sagt JA
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=True)
|
||||
def test_leereingabe_erlaubt_ja(self, mock_ask):
|
||||
ergebnis = pruef_ergebnis(False, "Leer?", "leereingabe_erlaubt", None)
|
||||
entscheidung = self.manager.verarbeite(ergebnis)
|
||||
|
||||
self.assertTrue(entscheidung.ok)
|
||||
self.assertEqual(entscheidung.aktion, "ok")
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 3. Leere Eingabe erlaubt → Nutzer sagt NEIN
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=False)
|
||||
def test_leereingabe_erlaubt_nein(self, mock_ask):
|
||||
ergebnis = pruef_ergebnis(False, "Leer?", "leereingabe_erlaubt", None)
|
||||
entscheidung = self.manager.verarbeite(ergebnis)
|
||||
|
||||
self.assertFalse(entscheidung.ok)
|
||||
self.assertEqual(entscheidung.aktion, "leereingabe_erlaubt")
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 4. Standarddatei vorschlagen → Nutzer sagt JA
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=True)
|
||||
def test_standarddatei_vorschlagen_ja(self, mock_ask):
|
||||
ergebnis = pruef_ergebnis(
|
||||
False,
|
||||
"Standarddatei verwenden?",
|
||||
"standarddatei_vorschlagen",
|
||||
"/tmp/std.txt",
|
||||
)
|
||||
|
||||
entscheidung = self.manager.verarbeite(ergebnis)
|
||||
|
||||
self.assertTrue(entscheidung.ok)
|
||||
self.assertEqual(entscheidung.aktion, "ok")
|
||||
self.assertEqual(entscheidung.kontext, "/tmp/std.txt")
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 5. Standarddatei vorschlagen → Nutzer sagt NEIN
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=False)
|
||||
def test_standarddatei_vorschlagen_nein(self, mock_ask):
|
||||
ergebnis = pruef_ergebnis(
|
||||
False,
|
||||
"Standarddatei verwenden?",
|
||||
"standarddatei_vorschlagen",
|
||||
"/tmp/std.txt",
|
||||
)
|
||||
|
||||
entscheidung = self.manager.verarbeite(ergebnis)
|
||||
|
||||
self.assertFalse(entscheidung.ok)
|
||||
self.assertEqual(entscheidung.aktion, "standarddatei_vorschlagen")
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 6. Temporäre Datei erzeugen → Nutzer sagt JA
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=True)
|
||||
def test_temporaer_erlaubt_ja(self, mock_ask):
|
||||
ergebnis = pruef_ergebnis(False, "Temporär?", "temporaer_erlaubt", None)
|
||||
entscheidung = self.manager.verarbeite(ergebnis)
|
||||
|
||||
self.assertTrue(entscheidung.ok)
|
||||
self.assertEqual(entscheidung.aktion, "temporaer_erzeugen")
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 7. Temporäre Datei erzeugen → Nutzer sagt NEIN
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=False)
|
||||
def test_temporaer_erlaubt_nein(self, mock_ask):
|
||||
ergebnis = pruef_ergebnis(False, "Temporär?", "temporaer_erlaubt", None)
|
||||
entscheidung = self.manager.verarbeite(ergebnis)
|
||||
|
||||
self.assertFalse(entscheidung.ok)
|
||||
self.assertEqual(entscheidung.aktion, "temporaer_erlaubt")
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 8. Layer unsichtbar → Nutzer sagt JA
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=True)
|
||||
@patch("sn_basis.modules.Pruefmanager.set_layer_visible")
|
||||
def test_layer_unsichtbar_ja(self, mock_set, mock_ask):
|
||||
fake_layer = object()
|
||||
ergebnis = pruef_ergebnis(False, "Layer unsichtbar", "layer_unsichtbar", fake_layer)
|
||||
|
||||
entscheidung = self.manager.verarbeite(ergebnis)
|
||||
|
||||
mock_set.assert_called_once_with(fake_layer, True)
|
||||
self.assertTrue(entscheidung.ok)
|
||||
self.assertEqual(entscheidung.aktion, "ok")
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 9. Layer unsichtbar → Nutzer sagt NEIN
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.Pruefmanager.ask_yes_no", return_value=False)
|
||||
def test_layer_unsichtbar_nein(self, mock_ask):
|
||||
fake_layer = object()
|
||||
ergebnis = pruef_ergebnis(False, "Layer unsichtbar", "layer_unsichtbar", fake_layer)
|
||||
|
||||
entscheidung = self.manager.verarbeite(ergebnis)
|
||||
|
||||
self.assertFalse(entscheidung.ok)
|
||||
self.assertEqual(entscheidung.aktion, "layer_unsichtbar")
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 10. Fehlerhafte Aktion → Fallback
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.Pruefmanager.warning")
|
||||
def test_unbekannte_aktion(self, mock_warn):
|
||||
ergebnis = pruef_ergebnis(False, "???", "unbekannt", None)
|
||||
entscheidung = self.manager.verarbeite(ergebnis)
|
||||
|
||||
mock_warn.assert_called_once()
|
||||
self.assertFalse(entscheidung.ok)
|
||||
self.assertEqual(entscheidung.aktion, "unbekannt")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
52
tests/test_qgis.bat
Normal file
52
tests/test_qgis.bat
Normal file
@@ -0,0 +1,52 @@
|
||||
@echo off
|
||||
setlocal
|
||||
echo BATCH WIRD AUSGEFÜHRT
|
||||
pause
|
||||
|
||||
echo ================================================
|
||||
echo Starte Tests in QGIS-Python-Umgebung
|
||||
echo ================================================
|
||||
|
||||
REM Pfad zur QGIS-Installation
|
||||
set QGIS_BIN=D:\OSGeo\bin
|
||||
|
||||
REM Prüfen, ob python-qgis.bat existiert
|
||||
if not exist "%QGIS_BIN%\python-qgis.bat" (
|
||||
echo.
|
||||
echo [FEHLER] python-qgis.bat wurde nicht gefunden!
|
||||
echo Erwarteter Pfad:
|
||||
echo %QGIS_BIN%\python-qgis.bat
|
||||
echo.
|
||||
echo Bitte korrigiere den Pfad in test_qgis.bat.
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo [INFO] QGIS-Python gefunden. Starte Tests...
|
||||
echo.
|
||||
|
||||
"%QGIS_BIN%\python-qgis.bat" -m coverage run run_tests.py
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo [FEHLER] Testlauf fehlgeschlagen.
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo ================================================
|
||||
echo Coverage HTML-Bericht wird erzeugt...
|
||||
echo ================================================
|
||||
|
||||
"%QGIS_BIN%\python-qgis.bat" -m coverage html
|
||||
|
||||
echo.
|
||||
echo Fertig!
|
||||
echo Öffne jetzt: coverage_html\index.html
|
||||
echo ================================================
|
||||
|
||||
pause
|
||||
endlocal
|
||||
60
tests/test_settings_logic.py
Normal file
60
tests/test_settings_logic.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# sn_basis/test/test_settings_logic.py
|
||||
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from sn_basis.functions.settings_logic import SettingsLogic
|
||||
|
||||
|
||||
class TestSettingsLogic(unittest.TestCase):
|
||||
|
||||
# -----------------------------------------------------
|
||||
# Test: load() liest alle Variablen über get_variable()
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.functions.settings_logic.get_variable")
|
||||
def test_load(self, mock_get):
|
||||
# Mock-Rückgabe für jede Variable
|
||||
mock_get.side_effect = lambda key, scope="project": f"wert_{key}"
|
||||
|
||||
logic = SettingsLogic()
|
||||
daten = logic.load()
|
||||
|
||||
# Alle Variablen müssen enthalten sein
|
||||
for key in SettingsLogic.VARIABLEN:
|
||||
self.assertIn(key, daten)
|
||||
self.assertEqual(daten[key], f"wert_{key}")
|
||||
|
||||
# get_variable muss für jede Variable genau einmal aufgerufen werden
|
||||
self.assertEqual(mock_get.call_count, len(SettingsLogic.VARIABLEN))
|
||||
|
||||
# -----------------------------------------------------
|
||||
# Test: save() ruft set_variable() nur für bekannte Keys auf
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.functions.settings_logic.set_variable")
|
||||
def test_save(self, mock_set):
|
||||
logic = SettingsLogic()
|
||||
|
||||
# Eingabedaten enthalten gültige und ungültige Keys
|
||||
daten = {
|
||||
"amt": "A1",
|
||||
"behoerde": "B1",
|
||||
"unbekannt": "IGNORIEREN",
|
||||
"gemeinden": "G1",
|
||||
}
|
||||
|
||||
logic.save(daten)
|
||||
|
||||
# set_variable muss nur für gültige Keys aufgerufen werden
|
||||
expected_calls = 3 # amt, behoerde, gemeinden
|
||||
self.assertEqual(mock_set.call_count, expected_calls)
|
||||
|
||||
# Prüfen, ob die richtigen Keys gespeichert wurden
|
||||
saved_keys = [call.args[0] for call in mock_set.call_args_list]
|
||||
self.assertIn("amt", saved_keys)
|
||||
self.assertIn("behoerde", saved_keys)
|
||||
self.assertIn("gemeinden", saved_keys)
|
||||
self.assertNotIn("unbekannt", saved_keys)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
81
tests/test_stilpruefer.py
Normal file
81
tests/test_stilpruefer.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# sn_basis/test/test_stilpruefer.py
|
||||
|
||||
import unittest
|
||||
import tempfile
|
||||
import os
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from sn_basis.modules.stilpruefer import Stilpruefer
|
||||
|
||||
|
||||
class TestStilpruefer(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.pruefer = Stilpruefer()
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 1. Keine Datei angegeben
|
||||
# -----------------------------------------------------
|
||||
def test_keine_datei_angegeben(self):
|
||||
result = self.pruefer.pruefe("")
|
||||
|
||||
self.assertTrue(result.ok)
|
||||
self.assertEqual(result.aktion, "ok")
|
||||
self.assertIn("Kein Stil angegeben", result.meldung)
|
||||
self.assertIsNone(result.kontext)
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 2. Datei existiert und ist .qml
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.stilpruefer.file_exists", return_value=True)
|
||||
def test_datei_existiert_mit_qml(self, mock_exists):
|
||||
with tempfile.NamedTemporaryFile(suffix=".qml", delete=False) as tmp:
|
||||
tmp_path = tmp.name
|
||||
|
||||
try:
|
||||
result = self.pruefer.pruefe(tmp_path)
|
||||
|
||||
self.assertTrue(result.ok)
|
||||
self.assertEqual(result.aktion, "stil_anwendbar")
|
||||
self.assertEqual(result.kontext, Path(tmp_path))
|
||||
|
||||
finally:
|
||||
os.remove(tmp_path)
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 3. Datei existiert, aber falsche Endung
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.stilpruefer.file_exists", return_value=True)
|
||||
def test_datei_existiert_falsche_endung(self, mock_exists):
|
||||
with tempfile.NamedTemporaryFile(suffix=".txt", delete=False) as tmp:
|
||||
tmp_path = tmp.name
|
||||
|
||||
try:
|
||||
result = self.pruefer.pruefe(tmp_path)
|
||||
|
||||
self.assertFalse(result.ok)
|
||||
self.assertEqual(result.aktion, "falsche_endung")
|
||||
self.assertIn(".qml", result.meldung)
|
||||
self.assertEqual(result.kontext, Path(tmp_path))
|
||||
|
||||
finally:
|
||||
os.remove(tmp_path)
|
||||
|
||||
# -----------------------------------------------------
|
||||
# 4. Datei existiert nicht
|
||||
# -----------------------------------------------------
|
||||
@patch("sn_basis.modules.stilpruefer.file_exists", return_value=False)
|
||||
def test_datei_existiert_nicht(self, mock_exists):
|
||||
fake_path = "/tmp/nichtvorhanden.qml"
|
||||
|
||||
result = self.pruefer.pruefe(fake_path)
|
||||
|
||||
self.assertFalse(result.ok)
|
||||
self.assertEqual(result.aktion, "datei_nicht_gefunden")
|
||||
self.assertIn("nicht gefunden", result.meldung)
|
||||
self.assertEqual(result.kontext, Path(fake_path))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user