Skip to content

Commit f35dc18

Browse files
committed
TST: Enhance Monte Carlo background map unit tests
- Refactored tests to improve error handling for missing environment attributes and invalid map providers. - Replaced warnings with exceptions for missing dependencies, ensuring stricter validation. - Added assertions to verify error messages for better clarity on issues encountered during background map fetching. - Introduced new tests for handling network errors and invalid map provider scenarios.
1 parent 709943f commit f35dc18

File tree

1 file changed

+103
-21
lines changed

1 file changed

+103
-21
lines changed

tests/unit/simulation/test_monte_carlo_plots_background.py

Lines changed: 103 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
# pylint: disable=unused-argument
22
import os
3-
import warnings
3+
import pytest
44
from unittest.mock import MagicMock, patch
55

66
import matplotlib.pyplot as plt
7-
import pytest
87

98
plt.rcParams.update({"figure.max_open_warning": 0})
109

@@ -13,6 +12,9 @@ def _post_test_file_cleanup():
1312
"""Clean monte carlo files after test session if they exist."""
1413
files_to_cleanup = [
1514
"monte_carlo_test.png",
15+
"monte_carlo_test.errors.txt",
16+
"monte_carlo_test.inputs.txt",
17+
"monte_carlo_test.outputs.txt",
1618
]
1719
for filepath in files_to_cleanup:
1820
if os.path.exists(filepath):
@@ -152,10 +154,12 @@ def test_ellipses_image_takes_precedence_over_background(
152154
_post_test_file_cleanup()
153155

154156

155-
def test_ellipses_background_no_environment():
157+
@patch("matplotlib.pyplot.show")
158+
def test_ellipses_background_no_environment(mock_show):
156159
"""Test that ValueError is raised when MonteCarlo object has no environment attribute.
157160
158161
This test creates a MonteCarlo object without an environment attribute.
162+
The function should raise ValueError when trying to fetch background map.
159163
"""
160164
from rocketpy.plots.monte_carlo_plots import _MonteCarloPlots
161165

@@ -172,16 +176,18 @@ def __init__(self):
172176
mock_monte_carlo = MockMonteCarlo()
173177
plots = _MonteCarloPlots(mock_monte_carlo)
174178

175-
with pytest.raises(
176-
ValueError, match="MonteCarlo object must have an 'environment' attribute"
177-
):
179+
with pytest.raises(ValueError) as exc_info:
178180
plots.ellipses(background="satellite")
181+
assert "environment" in str(exc_info.value).lower()
182+
assert "automatically fetching the background map" in str(exc_info.value)
179183

180184

181-
def test_ellipses_background_no_latitude_longitude():
185+
@patch("matplotlib.pyplot.show")
186+
def test_ellipses_background_no_latitude_longitude(mock_show):
182187
"""Test that ValueError is raised when environment has no latitude or longitude attributes.
183188
184189
This test creates a mock environment without latitude and longitude attributes.
190+
The function should raise ValueError when trying to fetch background map.
185191
"""
186192
from rocketpy.plots.monte_carlo_plots import _MonteCarloPlots
187193

@@ -191,20 +197,28 @@ def test_ellipses_background_no_latitude_longitude():
191197

192198
mock_monte_carlo = MagicMock()
193199
mock_monte_carlo.environment = mock_environment
200+
mock_monte_carlo.results = {
201+
"apogee_x": [100, 200, 300],
202+
"apogee_y": [100, 200, 300],
203+
"x_impact": [1000, 2000, 3000],
204+
"y_impact": [1000, 2000, 3000],
205+
}
206+
mock_monte_carlo.filename = "test"
194207

195208
plots = _MonteCarloPlots(mock_monte_carlo)
196209

197-
with pytest.raises(
198-
ValueError, match="Environment must have 'latitude' and 'longitude' attributes"
199-
):
210+
with pytest.raises(ValueError) as exc_info:
200211
plots.ellipses(background="satellite")
212+
assert "latitude" in str(exc_info.value).lower()
213+
assert "longitude" in str(exc_info.value).lower()
214+
assert "automatically fetching the background map" in str(exc_info.value)
201215

202216

203217
@patch("matplotlib.pyplot.show")
204218
def test_ellipses_background_contextily_not_installed(
205219
mock_show, monte_carlo_calisto_pre_loaded
206220
):
207-
"""Test that a warning is issued when contextily is not installed.
221+
"""Test that ImportError is raised when contextily is not installed.
208222
209223
Parameters
210224
----------
@@ -226,16 +240,9 @@ def mock_import_optional_dependency(name):
226240
"rocketpy.plots.monte_carlo_plots.import_optional_dependency",
227241
side_effect=mock_import_optional_dependency,
228242
):
229-
with warnings.catch_warnings(record=True) as w:
230-
warnings.simplefilter("always")
231-
result = monte_carlo_calisto_pre_loaded.plots.ellipses(
232-
background="satellite"
233-
)
234-
assert result is None
235-
assert len(w) > 0
236-
assert any(
237-
"contextily" in str(warning.message).lower() for warning in w
238-
)
243+
with pytest.raises(ImportError) as exc_info:
244+
monte_carlo_calisto_pre_loaded.plots.ellipses(background="satellite")
245+
assert "contextily" in str(exc_info.value).lower()
239246
finally:
240247
_post_test_file_cleanup()
241248

@@ -286,3 +293,78 @@ def test_ellipses_background_save(mock_show, monte_carlo_calisto_pre_loaded):
286293
assert os.path.exists("monte_carlo_test.png")
287294
finally:
288295
_post_test_file_cleanup()
296+
297+
298+
@patch("matplotlib.pyplot.show")
299+
def test_ellipses_background_invalid_provider(
300+
mock_show, monte_carlo_calisto_pre_loaded
301+
):
302+
"""Test that ValueError is raised when an invalid map provider is specified.
303+
304+
Parameters
305+
----------
306+
mock_show :
307+
Mocks the matplotlib.pyplot.show() function to avoid showing the plots.
308+
monte_carlo_calisto_pre_loaded : MonteCarlo
309+
The MonteCarlo object, this is a pytest fixture.
310+
"""
311+
try:
312+
with pytest.raises(ValueError) as exc_info:
313+
monte_carlo_calisto_pre_loaded.plots.ellipses(
314+
background="Invalid.Provider.Name"
315+
)
316+
assert "Invalid map provider" in str(exc_info.value)
317+
assert "Invalid.Provider.Name" in str(exc_info.value)
318+
assert (
319+
"satellite" in str(exc_info.value)
320+
or "street" in str(exc_info.value)
321+
or "terrain" in str(exc_info.value)
322+
)
323+
finally:
324+
_post_test_file_cleanup()
325+
326+
327+
@patch("matplotlib.pyplot.show")
328+
def test_ellipses_background_bounds2img_failure(
329+
mock_show, monte_carlo_calisto_pre_loaded
330+
):
331+
"""Test that RuntimeError is raised when bounds2img fails to fetch map tiles.
332+
333+
Parameters
334+
----------
335+
mock_show :
336+
Mocks the matplotlib.pyplot.show() function to avoid showing the plots.
337+
monte_carlo_calisto_pre_loaded : MonteCarlo
338+
The MonteCarlo object, this is a pytest fixture.
339+
"""
340+
try:
341+
from rocketpy.tools import import_optional_dependency as original_import
342+
import contextily
343+
344+
# Create a mock contextily module with a failing bounds2img
345+
mock_contextily = MagicMock()
346+
mock_contextily.providers = contextily.providers
347+
348+
def mock_bounds2img(*args, **kwargs):
349+
raise ConnectionError("Network error: Unable to fetch tiles")
350+
351+
mock_contextily.bounds2img = mock_bounds2img
352+
353+
def mock_import_optional_dependency(name):
354+
if name == "contextily":
355+
return mock_contextily
356+
return original_import(name)
357+
358+
with patch(
359+
"rocketpy.plots.monte_carlo_plots.import_optional_dependency",
360+
side_effect=mock_import_optional_dependency,
361+
):
362+
with pytest.raises(RuntimeError) as exc_info:
363+
monte_carlo_calisto_pre_loaded.plots.ellipses(background="satellite")
364+
assert "Failed to fetch background map tiles" in str(exc_info.value)
365+
assert "satellite" in str(exc_info.value)
366+
assert "Network connectivity" in str(
367+
exc_info.value
368+
) or "Service unavailability" in str(exc_info.value)
369+
finally:
370+
_post_test_file_cleanup()

0 commit comments

Comments
 (0)