verfahrensgebiet aus Flst
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
"""sn_verfahrensgebiet/tests/test_gemarkung_alkis.py
|
||||
|
||||
Unit-Tests für :mod:`sn_verfahrensgebiet.functions.gemarkung_alkis`.
|
||||
|
||||
Getestete Szenarien:
|
||||
|
||||
Erfolgsfall:
|
||||
- WFS-Layer gültig + Features mit Schlüssel → Liste mit Tupeln
|
||||
- Schlüssel werden dedupliziert und sortiert zurückgegeben
|
||||
- ``gemarkung_schluessel_by_bbox`` gibt nur Nummern (keine Tupel) zurück
|
||||
|
||||
Fehlerfälle:
|
||||
- WFS-Layer nicht gültig (beide Varianten) → Fallback-Ladeversuch
|
||||
- Fallback-Layer ebenfalls ungültig → leere Liste
|
||||
- Alle Layer leer (featureCount == 0) → client-seitige Filterung schlägt leer
|
||||
- Feature ohne Schlüssel-Attribut wird übersprungen
|
||||
- Exception beim Layer-Laden → leere Liste
|
||||
"""
|
||||
|
||||
import sys
|
||||
import types
|
||||
import unittest
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Minimales QGIS-Mock-Setup
|
||||
# ---------------------------------------------------------------------------
|
||||
if "qgis" not in sys.modules:
|
||||
qgis_mod = types.ModuleType("qgis")
|
||||
qgis_core = types.ModuleType("qgis.core")
|
||||
qgis_utils = types.ModuleType("qgis.utils")
|
||||
qgis_utils.iface = types.SimpleNamespace()
|
||||
qgis_utils.plugins = {}
|
||||
qgis_mod.utils = qgis_utils
|
||||
qgis_mod.core = qgis_core
|
||||
sys.modules["qgis"] = qgis_mod
|
||||
sys.modules["qgis.core"] = qgis_core
|
||||
sys.modules["qgis.utils"] = qgis_utils
|
||||
|
||||
from sn_verfahrensgebiet.functions.gemarkung_alkis import (
|
||||
gemarkung_schluessel_und_namen_by_bbox,
|
||||
gemarkung_schluessel_by_bbox,
|
||||
_extract_schluessel_und_name,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Dummies
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class _DummyRect:
|
||||
def xMinimum(self): return 414000.0
|
||||
def yMinimum(self): return 5657000.0
|
||||
def xMaximum(self): return 415000.0
|
||||
def yMaximum(self): return 5658000.0
|
||||
|
||||
|
||||
class _DummyFeature:
|
||||
def __init__(self, attrs: dict):
|
||||
self._attrs = attrs
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._attrs.get(key, None)
|
||||
|
||||
|
||||
def _make_layer(valid=True, feature_count=2, features=None):
|
||||
layer = MagicMock()
|
||||
layer.isValid.return_value = valid
|
||||
layer.featureCount.return_value = feature_count if valid else 0
|
||||
layer.getFeatures.return_value = features or []
|
||||
return layer
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests: _extract_schluessel_und_name
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestExtractSchluesselUndName(unittest.TestCase):
|
||||
|
||||
def test_standard_attribute(self):
|
||||
feat = _DummyFeature({"schluessel_gemarkungsnummer": "1234", "bezeichnung": "Mustergemarkung"})
|
||||
nr, name = _extract_schluessel_und_name(feat)
|
||||
self.assertEqual(nr, "1234")
|
||||
self.assertEqual(name, "Mustergemarkung")
|
||||
|
||||
def test_fallback_attribute(self):
|
||||
feat = _DummyFeature({"gemarkungsnummer": "5678", "gemarkung_bezeichnung": "Alternativ"})
|
||||
nr, name = _extract_schluessel_und_name(feat)
|
||||
self.assertEqual(nr, "5678")
|
||||
self.assertEqual(name, "Alternativ")
|
||||
|
||||
def test_missing_attribute_returns_empty(self):
|
||||
feat = _DummyFeature({})
|
||||
nr, name = _extract_schluessel_und_name(feat)
|
||||
self.assertEqual(nr, "")
|
||||
self.assertEqual(name, "")
|
||||
|
||||
def test_none_value_returns_empty(self):
|
||||
feat = _DummyFeature({"schluessel_gemarkungsnummer": None, "bezeichnung": None})
|
||||
nr, name = _extract_schluessel_und_name(feat)
|
||||
self.assertEqual(nr, "")
|
||||
self.assertEqual(name, "")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests: gemarkung_schluessel_und_namen_by_bbox
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestGemarkungSchluesselbbox(unittest.TestCase):
|
||||
|
||||
@patch("sn_verfahrensgebiet.functions.gemarkung_alkis._load_gemarkung_layer_with_bbox")
|
||||
def test_success_bbox_filter(self, mock_load_bbox):
|
||||
"""WFS-BBox-Filter liefert Features → korrekte Tupel-Liste."""
|
||||
feat1 = _DummyFeature({"schluessel_gemarkungsnummer": "1234", "bezeichnung": "Alpha"})
|
||||
feat2 = _DummyFeature({"schluessel_gemarkungsnummer": "5678", "bezeichnung": "Beta"})
|
||||
mock_load_bbox.return_value = _make_layer(valid=True, features=[feat1, feat2])
|
||||
|
||||
result = gemarkung_schluessel_und_namen_by_bbox(_DummyRect())
|
||||
|
||||
self.assertEqual(result, [("1234", "Alpha"), ("5678", "Beta")])
|
||||
|
||||
@patch("sn_verfahrensgebiet.functions.gemarkung_alkis._load_all_gemarkung_layer")
|
||||
@patch("sn_verfahrensgebiet.functions.gemarkung_alkis._load_gemarkung_layer_with_bbox")
|
||||
def test_fallback_when_bbox_fails(self, mock_load_bbox, mock_load_all):
|
||||
"""BBox-Filter schlägt fehl → Fallback auf Volllade + client-seitige Filterung."""
|
||||
mock_load_bbox.return_value = None
|
||||
|
||||
feat1 = _DummyFeature({"schluessel_gemarkungsnummer": "9999", "bezeichnung": "Fallback"})
|
||||
all_layer = _make_layer(valid=True, features=[feat1])
|
||||
# getFeatures mit FilterRect soll dasselbe zurückgeben
|
||||
all_layer.getFeatures.return_value = [feat1]
|
||||
mock_load_all.return_value = all_layer
|
||||
|
||||
result = gemarkung_schluessel_und_namen_by_bbox(_DummyRect())
|
||||
|
||||
self.assertEqual(len(result), 1)
|
||||
self.assertEqual(result[0][0], "9999")
|
||||
|
||||
@patch("sn_verfahrensgebiet.functions.gemarkung_alkis._load_all_gemarkung_layer")
|
||||
@patch("sn_verfahrensgebiet.functions.gemarkung_alkis._load_gemarkung_layer_with_bbox")
|
||||
def test_both_layers_fail_returns_empty(self, mock_load_bbox, mock_load_all):
|
||||
"""Beide Lade-Strategien scheitern → leere Liste."""
|
||||
mock_load_bbox.return_value = None
|
||||
mock_load_all.return_value = None
|
||||
|
||||
result = gemarkung_schluessel_und_namen_by_bbox(_DummyRect())
|
||||
self.assertEqual(result, [])
|
||||
|
||||
@patch("sn_verfahrensgebiet.functions.gemarkung_alkis._load_gemarkung_layer_with_bbox")
|
||||
def test_deduplication_and_sorting(self, mock_load_bbox):
|
||||
"""Doppelte Schlüssel werden dedupliziert, Ergebnis ist sortiert."""
|
||||
feat_a = _DummyFeature({"schluessel_gemarkungsnummer": "2222", "bezeichnung": "Z"})
|
||||
feat_b = _DummyFeature({"schluessel_gemarkungsnummer": "1111", "bezeichnung": "A"})
|
||||
feat_dup = _DummyFeature({"schluessel_gemarkungsnummer": "2222", "bezeichnung": "Z2"})
|
||||
mock_load_bbox.return_value = _make_layer(features=[feat_a, feat_b, feat_dup])
|
||||
|
||||
result = gemarkung_schluessel_und_namen_by_bbox(_DummyRect())
|
||||
|
||||
nummern = [r[0] for r in result]
|
||||
self.assertEqual(nummern, sorted(nummern))
|
||||
self.assertEqual(len(result), 2)
|
||||
|
||||
@patch("sn_verfahrensgebiet.functions.gemarkung_alkis._load_gemarkung_layer_with_bbox")
|
||||
def test_feature_without_schluessel_skipped(self, mock_load_bbox):
|
||||
"""Feature ohne Schlüssel-Attribut wird übersprungen."""
|
||||
feat_ok = _DummyFeature({"schluessel_gemarkungsnummer": "1234", "bezeichnung": "X"})
|
||||
feat_bad = _DummyFeature({})
|
||||
mock_load_bbox.return_value = _make_layer(features=[feat_ok, feat_bad])
|
||||
|
||||
result = gemarkung_schluessel_und_namen_by_bbox(_DummyRect())
|
||||
|
||||
self.assertEqual(len(result), 1)
|
||||
self.assertEqual(result[0][0], "1234")
|
||||
|
||||
@patch("sn_verfahrensgebiet.functions.gemarkung_alkis._load_gemarkung_layer_with_bbox")
|
||||
def test_exception_returns_empty(self, mock_load_bbox):
|
||||
"""Exception im Ladevorgang → leere Liste (kein Crash)."""
|
||||
mock_load_bbox.side_effect = RuntimeError("WFS-Fehler")
|
||||
|
||||
result = gemarkung_schluessel_und_namen_by_bbox(_DummyRect())
|
||||
self.assertEqual(result, [])
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests: gemarkung_schluessel_by_bbox (Convenience-Wrapper)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestGemarkungSchluesselnurNummern(unittest.TestCase):
|
||||
|
||||
@patch("sn_verfahrensgebiet.functions.gemarkung_alkis.gemarkung_schluessel_und_namen_by_bbox")
|
||||
def test_returns_only_nummern(self, mock_full):
|
||||
mock_full.return_value = [("1234", "Alpha"), ("5678", "Beta")]
|
||||
|
||||
result = gemarkung_schluessel_by_bbox(_DummyRect())
|
||||
|
||||
self.assertEqual(result, ["1234", "5678"])
|
||||
|
||||
@patch("sn_verfahrensgebiet.functions.gemarkung_alkis.gemarkung_schluessel_und_namen_by_bbox")
|
||||
def test_empty_input_returns_empty(self, mock_full):
|
||||
mock_full.return_value = []
|
||||
|
||||
result = gemarkung_schluessel_by_bbox(_DummyRect())
|
||||
self.assertEqual(result, [])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user