Skip to content

Commit a4e0e0c

Browse files
committed
Shifts test to pytest
1 parent 2da5952 commit a4e0e0c

1 file changed

Lines changed: 61 additions & 48 deletions

File tree

climada/trajectories/test/test_impact_calc_strat.py

Lines changed: 61 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,65 +20,78 @@
2020
2121
"""
2222

23-
import unittest
2423
from unittest.mock import MagicMock, patch
2524

25+
import pytest
26+
2627
from climada.engine import Impact
2728
from climada.entity import ImpactFuncSet
2829
from climada.entity.exposures import Exposures
2930
from climada.hazard import Hazard
3031
from climada.trajectories import Snapshot
31-
from climada.trajectories.impact_calc_strat import ImpactCalcComputation
32-
33-
34-
class TestImpactCalcComputation(unittest.TestCase):
35-
def setUp(self):
36-
self.mock_snapshot0 = MagicMock(spec=Snapshot)
37-
self.mock_snapshot0.exposure = MagicMock(spec=Exposures)
38-
self.mock_snapshot0.hazard = MagicMock(spec=Hazard)
39-
self.mock_snapshot0.impfset = MagicMock(spec=ImpactFuncSet)
40-
self.mock_snapshot1 = MagicMock(spec=Snapshot)
41-
self.mock_snapshot1.exposure = MagicMock(spec=Exposures)
42-
self.mock_snapshot1.hazard = MagicMock(spec=Hazard)
43-
self.mock_snapshot1.impfset = MagicMock(spec=ImpactFuncSet)
44-
45-
self.impact_calc_computation = ImpactCalcComputation()
46-
47-
@patch.object(ImpactCalcComputation, "compute_impacts_pre_transfer")
48-
def test_compute_impacts(self, mock_calculate_impacts_for_snapshots):
49-
mock_impacts = MagicMock(spec=Impact)
50-
mock_calculate_impacts_for_snapshots.return_value = mock_impacts
51-
52-
result = self.impact_calc_computation.compute_impacts(
53-
exp=self.mock_snapshot0.exposure,
54-
haz=self.mock_snapshot0.hazard,
55-
vul=self.mock_snapshot0.impfset,
56-
)
32+
from climada.trajectories.impact_calc_strat import (
33+
ImpactCalcComputation,
34+
ImpactComputationStrategy,
35+
)
36+
37+
# --- Fixtures ---
38+
39+
40+
@pytest.fixture
41+
def mock_snapshot():
42+
"""Provides a snapshot with mocked exposure, hazard, and impact functions."""
43+
snap = MagicMock(spec=Snapshot)
44+
snap.exposure = MagicMock(spec=Exposures)
45+
snap.hazard = MagicMock(spec=Hazard)
46+
snap.impfset = MagicMock(spec=ImpactFuncSet)
47+
return snap
5748

58-
self.assertEqual(result, mock_impacts)
59-
mock_calculate_impacts_for_snapshots.assert_called_once_with(
60-
self.mock_snapshot0.exposure,
61-
self.mock_snapshot0.hazard,
62-
self.mock_snapshot0.impfset,
63-
)
6449

65-
def test_calculate_impacts_for_snapshots(self):
66-
mock_imp_E0H0 = MagicMock(spec=Impact)
50+
@pytest.fixture
51+
def strategy():
52+
"""Provides an instance of the ImpactCalcComputation strategy."""
53+
return ImpactCalcComputation()
6754

68-
with patch(
69-
"climada.trajectories.impact_calc_strat.ImpactCalc"
70-
) as mock_impact_calc:
71-
mock_impact_calc.return_value.impact.side_effect = [mock_imp_E0H0]
7255

73-
result = self.impact_calc_computation.compute_impacts_pre_transfer(
74-
exp=self.mock_snapshot0.exposure,
75-
haz=self.mock_snapshot0.hazard,
76-
vul=self.mock_snapshot0.impfset,
77-
)
56+
# --- Tests ---
57+
def test_interface_compliance(strategy):
58+
"""Ensure the class correctly inherits from the Abstract Base Class."""
59+
assert isinstance(strategy, ImpactComputationStrategy)
60+
assert isinstance(strategy, ImpactCalcComputation)
61+
62+
63+
def test_compute_impacts(strategy, mock_snapshot):
64+
"""Test that compute_impacts calls the pre-transfer method correctly."""
65+
mock_impacts = MagicMock(spec=Impact)
66+
67+
# We patch the ImpactCalc within trajectories
68+
with patch("climada.trajectories.impact_calc_strat.ImpactCalc") as mock_ImpactCalc:
69+
mock_ImpactCalc.return_value.impact.return_value = mock_impacts
70+
result = strategy.compute_impacts(
71+
exp=mock_snapshot.exposure,
72+
haz=mock_snapshot.hazard,
73+
vul=mock_snapshot.impfset,
74+
)
75+
mock_ImpactCalc.assert_called_once_with(
76+
exposures=mock_snapshot.exposure,
77+
impfset=mock_snapshot.impfset,
78+
hazard=mock_snapshot.hazard,
79+
)
80+
mock_ImpactCalc.return_value.impact.assert_called_once()
81+
assert result == mock_impacts
82+
7883

79-
self.assertEqual(result, mock_imp_E0H0)
84+
def test_cannot_instantiate_abstract_base_class():
85+
"""Ensure ImpactComputationStrategy cannot be instantiated directly."""
86+
with pytest.raises(TypeError, match="Can't instantiate abstract class"):
87+
ImpactComputationStrategy() # type: ignore
8088

8189

82-
if __name__ == "__main__":
83-
TESTS = unittest.TestLoader().loadTestsFromTestCase(TestImpactCalcComputation)
84-
unittest.TextTestRunner(verbosity=2).run(TESTS)
90+
@pytest.mark.parametrize("invalid_input", [None, 123, "string"])
91+
def test_compute_impacts_type_errors(strategy, invalid_input):
92+
"""
93+
Smoke test: Ensure that if ImpactCalc raises errors due to bad input,
94+
the strategy correctly propagates them.
95+
"""
96+
with pytest.raises(AttributeError):
97+
strategy.compute_impacts(invalid_input, invalid_input, invalid_input)

0 commit comments

Comments
 (0)