From c5d382ee81edc0727d07907c932970c762ec33bd Mon Sep 17 00:00:00 2001 From: Luan Taraschi <130802253+luantaraschi@users.noreply.github.com> Date: Thu, 20 Aug 2026 09:58:20 -0300 Subject: [PATCH] test(visualization): isolate optional dependency mocks (#897) * test(visualization): isolate optional dependency mocks * test(visualization): stop requiring Plotly in unit tests Removing the global sys.modules stubs left the tests that patch `...go.Bar`, or call a visualizer, with nothing standing in for the module level `px` and `go` aliases. Those are None when Plotly is missing, so patch resolution and _check_dependencies() both failed. Add a helper that substitutes a double only for the aliases that are None, leaving the real module in place when Plotly is installed. --------- --- tests/visualization/__init__.py | 0 tests/visualization/_plotly_doubles.py | 29 +++ .../test_kg_visualizer_normalize_graph.py | 85 ++++---- .../test_optional_dependencies.py | 188 +++++++----------- tests/visualization/test_visualization.py | 24 +-- .../test_visualization_advanced.py | 55 ++--- .../test_visualization_comprehensive.py | 51 ++--- 7 files changed, 187 insertions(+), 245 deletions(-) create mode 100644 tests/visualization/__init__.py create mode 100644 tests/visualization/_plotly_doubles.py diff --git a/tests/visualization/__init__.py b/tests/visualization/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/visualization/_plotly_doubles.py b/tests/visualization/_plotly_doubles.py new file mode 100644 index 00000000..82465e15 --- /dev/null +++ b/tests/visualization/_plotly_doubles.py @@ -0,0 +1,29 @@ +"""Shared helper for visualization tests. + +The visualization modules treat Plotly as optional: they bind ``px``, ``go`` and +``make_subplots`` to ``None`` when the import fails, and raise ``ProcessingError`` +from ``_check_dependencies()``. Tests that exercise a Plotly-backed path need +those names to be usable, otherwise ``patch("...go.Figure")`` fails on ``None`` +and the visualizers refuse to run. + +``plotly_doubles`` fills in a double for each alias that is ``None``, so the +tests describe their own requirements instead of depending on whether Plotly +happens to be installed. When Plotly is installed the aliases are left alone and +the patches keep asserting against the real attribute names. +""" + +from contextlib import ExitStack, contextmanager +from unittest.mock import MagicMock, patch + +PLOTLY_ALIASES = ("px", "go", "make_subplots") + + +@contextmanager +def plotly_doubles(*modules): + """Stand in for the module-level Plotly aliases that are unavailable.""" + with ExitStack() as stack: + for module in modules: + for alias in PLOTLY_ALIASES: + if getattr(module, alias, "unused") is None: + stack.enter_context(patch.object(module, alias, MagicMock())) + yield diff --git a/tests/visualization/test_kg_visualizer_normalize_graph.py b/tests/visualization/test_kg_visualizer_normalize_graph.py index 055bcdc3..9ff130f5 100644 --- a/tests/visualization/test_kg_visualizer_normalize_graph.py +++ b/tests/visualization/test_kg_visualizer_normalize_graph.py @@ -9,27 +9,16 @@ and must raise a clear ProcessingError for anything else. """ import contextlib -import sys import unittest from dataclasses import dataclass, field from typing import List from unittest.mock import MagicMock, patch -# --------------------------------------------------------------------------- -# Stub out heavy optional deps before importing the module under test -# --------------------------------------------------------------------------- -sys.modules.setdefault("matplotlib", MagicMock()) -sys.modules.setdefault("matplotlib.pyplot", MagicMock()) -sys.modules.setdefault("matplotlib.patches", MagicMock()) -sys.modules.setdefault("plotly", MagicMock()) -sys.modules.setdefault("plotly.express", MagicMock()) -sys.modules.setdefault("plotly.graph_objects", MagicMock()) -sys.modules.setdefault("plotly.subplots", MagicMock()) -sys.modules.setdefault("graphviz", MagicMock()) -sys.modules.setdefault("seaborn", MagicMock()) - from semantica.utils.exceptions import ProcessingError # noqa: E402 +from semantica.visualization import kg_visualizer # noqa: E402 from semantica.visualization.kg_visualizer import KGVisualizer # noqa: E402 +from tests.visualization._plotly_doubles import plotly_doubles # noqa: E402 + # --------------------------------------------------------------------------- # Minimal fixtures @@ -191,10 +180,6 @@ class TestVisualizeNetworkAcceptsKGObject(unittest.TestCase): def _run_visualize_network(self, graph_arg): """Run visualize_network with all Plotly internals mocked.""" mock_fig = MagicMock() - mock_go = sys.modules["plotly.graph_objects"] - mock_go.Figure.return_value = mock_fig - mock_go.Scatter.return_value = MagicMock() - mock_go.Layout.return_value = MagicMock() viz = _make_viz() @@ -207,6 +192,10 @@ class TestVisualizeNetworkAcceptsKGObject(unittest.TestCase): # ColorPalette helpers with ( + plotly_doubles(kg_visualizer), + patch("semantica.visualization.kg_visualizer.go.Figure", return_value=mock_fig), + patch("semantica.visualization.kg_visualizer.go.Scatter"), + patch("semantica.visualization.kg_visualizer.go.Layout"), patch( "semantica.visualization.kg_visualizer.ColorPalette.get_entity_type_colors", return_value={"Person": "#ff0000"}, @@ -254,9 +243,12 @@ class TestAllVisualizeMethodsAcceptKGObject(unittest.TestCase): self.viz._normalize_graph = MagicMock(return_value=GRAPH_DICT) self.viz._visualize_network_plotly = MagicMock(return_value=MagicMock()) communities = {"node_assignments": {"e1": 0, "e2": 1}, "num_communities": 2} - with patch( - "semantica.visualization.kg_visualizer.ColorPalette.get_community_colors", - return_value=["#ff0000", "#00ff00"], + with ( + plotly_doubles(kg_visualizer), + patch( + "semantica.visualization.kg_visualizer.ColorPalette.get_community_colors", + return_value=["#ff0000", "#00ff00"], + ), ): self.viz.visualize_communities(self.kg, communities=communities) self.viz._normalize_graph.assert_called_once_with(self.kg) @@ -264,22 +256,24 @@ class TestAllVisualizeMethodsAcceptKGObject(unittest.TestCase): def test_visualize_centrality_accepts_kg_object(self): self.viz._normalize_graph = MagicMock(return_value=GRAPH_DICT) self.viz._visualize_network_plotly = MagicMock(return_value=MagicMock()) - self.viz.visualize_centrality(self.kg, centrality={"centrality": {}}) + with plotly_doubles(kg_visualizer): + self.viz.visualize_centrality(self.kg, centrality={"centrality": {}}) self.viz._normalize_graph.assert_called_once_with(self.kg) def test_visualize_entity_types_accepts_kg_object(self): self.viz._normalize_graph = MagicMock(return_value=GRAPH_DICT) - mock_px = sys.modules["plotly.express"] - mock_px.bar.return_value = MagicMock() - self.viz.visualize_entity_types(self.kg) + with plotly_doubles(kg_visualizer), patch("semantica.visualization.kg_visualizer.px.bar"): + self.viz.visualize_entity_types(self.kg) self.viz._normalize_graph.assert_called_once_with(self.kg) def test_visualize_relationship_matrix_accepts_kg_object(self): self.viz._normalize_graph = MagicMock(return_value=GRAPH_DICT) - mock_go = sys.modules["plotly.graph_objects"] - mock_go.Figure.return_value = MagicMock() - mock_go.Heatmap.return_value = MagicMock() - self.viz.visualize_relationship_matrix(self.kg) + with ( + plotly_doubles(kg_visualizer), + patch("semantica.visualization.kg_visualizer.go.Figure"), + patch("semantica.visualization.kg_visualizer.go.Heatmap"), + ): + self.viz.visualize_relationship_matrix(self.kg) self.viz._normalize_graph.assert_called_once_with(self.kg) @@ -361,10 +355,6 @@ class TestFormalKnowledgeGraphType(unittest.TestCase): def _run_visualize_network(self, graph_arg): mock_fig = MagicMock() - mock_go = sys.modules["plotly.graph_objects"] - mock_go.Figure.return_value = mock_fig - mock_go.Scatter.return_value = MagicMock() - mock_go.Layout.return_value = MagicMock() viz = _make_viz() fake_pos = {"e1": (0.0, 0.0), "e2": (1.0, 1.0)} viz.force_layout = MagicMock() @@ -372,6 +362,10 @@ class TestFormalKnowledgeGraphType(unittest.TestCase): viz.hierarchical_layout = MagicMock() viz.circular_layout = MagicMock() with ( + plotly_doubles(kg_visualizer), + patch("semantica.visualization.kg_visualizer.go.Figure", return_value=mock_fig), + patch("semantica.visualization.kg_visualizer.go.Scatter"), + patch("semantica.visualization.kg_visualizer.go.Layout"), patch( "semantica.visualization.kg_visualizer.ColorPalette.get_entity_type_colors", return_value={"Person": "#ff0000"}, @@ -392,9 +386,12 @@ class TestFormalKnowledgeGraphType(unittest.TestCase): viz._normalize_graph = MagicMock(return_value=GRAPH_DICT) viz._visualize_network_plotly = MagicMock(return_value=MagicMock()) communities = {"node_assignments": {"e1": 0, "e2": 1}, "num_communities": 2} - with patch( - "semantica.visualization.kg_visualizer.ColorPalette.get_community_colors", - return_value=["#ff0000", "#00ff00"], + with ( + plotly_doubles(kg_visualizer), + patch( + "semantica.visualization.kg_visualizer.ColorPalette.get_community_colors", + return_value=["#ff0000", "#00ff00"], + ), ): viz.visualize_communities(kg, communities=communities) viz._normalize_graph.assert_called_once_with(kg) @@ -404,24 +401,28 @@ class TestFormalKnowledgeGraphType(unittest.TestCase): viz = _make_viz() viz._normalize_graph = MagicMock(return_value=GRAPH_DICT) viz._visualize_network_plotly = MagicMock(return_value=MagicMock()) - viz.visualize_centrality(kg, centrality={"centrality": {}}) + with plotly_doubles(kg_visualizer): + viz.visualize_centrality(kg, centrality={"centrality": {}}) viz._normalize_graph.assert_called_once_with(kg) def test_visualize_entity_types_accepts_knowledge_graph(self): kg = self._make_kg() viz = _make_viz() viz._normalize_graph = MagicMock(return_value=GRAPH_DICT) - sys.modules["plotly.express"].bar.return_value = MagicMock() - viz.visualize_entity_types(kg) + with plotly_doubles(kg_visualizer), patch("semantica.visualization.kg_visualizer.px.bar"): + viz.visualize_entity_types(kg) viz._normalize_graph.assert_called_once_with(kg) def test_visualize_relationship_matrix_accepts_knowledge_graph(self): kg = self._make_kg() viz = _make_viz() viz._normalize_graph = MagicMock(return_value=GRAPH_DICT) - sys.modules["plotly.graph_objects"].Figure.return_value = MagicMock() - sys.modules["plotly.graph_objects"].Heatmap.return_value = MagicMock() - viz.visualize_relationship_matrix(kg) + with ( + plotly_doubles(kg_visualizer), + patch("semantica.visualization.kg_visualizer.go.Figure"), + patch("semantica.visualization.kg_visualizer.go.Heatmap"), + ): + viz.visualize_relationship_matrix(kg) viz._normalize_graph.assert_called_once_with(kg) def test_knowledge_graph_importable_from_kg_module(self): diff --git a/tests/visualization/test_optional_dependencies.py b/tests/visualization/test_optional_dependencies.py index bc390ecc..af41e5ca 100644 --- a/tests/visualization/test_optional_dependencies.py +++ b/tests/visualization/test_optional_dependencies.py @@ -1,149 +1,115 @@ -import unittest -from unittest.mock import MagicMock, patch +import importlib import sys +import unittest +from contextlib import contextmanager +from unittest.mock import patch + import numpy as np -# Helper to mock modules -def mock_module(name): - m = MagicMock() - sys.modules[name] = m - return m +from tests.visualization._plotly_doubles import plotly_doubles + + +@contextmanager +def import_without(module_name, *dependencies): + """Import a module with selected optional dependencies unavailable.""" + package_name, attribute = module_name.rsplit(".", 1) + package = importlib.import_module(package_name) + missing = object() + original_module = sys.modules.pop(module_name, missing) + original_attribute = getattr(package, attribute, missing) + + try: + with patch.dict(sys.modules, {name: None for name in dependencies}): + yield importlib.import_module(module_name) + finally: + sys.modules.pop(module_name, None) + if original_module is not missing: + sys.modules[module_name] = original_module + if original_attribute is missing: + package.__dict__.pop(attribute, None) + else: + setattr(package, attribute, original_attribute) + class TestOptionalDependencies(unittest.TestCase): - - @classmethod - def setUpClass(cls): - # Mock heavy/problematic dependencies globally to prevent environment crashes - # We use a dict to save original modules if they exist, but for this test file - # we generally want to run in a controlled "clean" environment. - cls.modules_to_patch = [ - 'sklearn', 'sklearn.decomposition', 'sklearn.manifold', - 'scipy', 'scipy.optimize', - 'matplotlib', 'matplotlib.pyplot', 'matplotlib.patches', - 'plotly', 'plotly.express', 'plotly.graph_objects', 'plotly.subplots', - 'networkx', 'seaborn' - ] - - cls.original_modules = {} - for mod in cls.modules_to_patch: - if mod in sys.modules: - cls.original_modules[mod] = sys.modules[mod] - sys.modules[mod] = MagicMock() - - @classmethod - def tearDownClass(cls): - # Restore original modules - for mod in cls.modules_to_patch: - if mod in cls.original_modules: - sys.modules[mod] = cls.original_modules[mod] - else: - del sys.modules[mod] - - def setUp(self): - # Clear cached visualization modules to ensure fresh imports - self.viz_modules = [ - 'semantica.visualization.embedding_visualizer', - 'semantica.visualization.ontology_visualizer', - 'semantica.visualization.kg_visualizer', - 'semantica.visualization.utils.export_formats' - ] - for mod in self.viz_modules: - if mod in sys.modules: - del sys.modules[mod] def test_embedding_visualizer_without_umap(self): """Test EmbeddingVisualizer behavior when umap is missing.""" - # Ensure umap is missing - with patch.dict(sys.modules, {'umap': None}): - from semantica.visualization.embedding_visualizer import EmbeddingVisualizer - - # Setup PCA mock to verify fallback - mock_pca_class = sys.modules['sklearn.decomposition'].PCA - mock_pca_instance = mock_pca_class.return_value - # Configure fit_transform to return correct shape (n_samples, 2) - mock_pca_instance.fit_transform.return_value = np.zeros((4, 2)) - - viz = EmbeddingVisualizer() - # Use numpy array! - embeddings = np.array([[0, 1, 2], [1, 0, 3], [0, 0, 0], [1, 1, 1]]) - - # Should fallback to PCA when method="umap" is used but umap is None - # The code logs a warning and uses PCA - viz.visualize_2d_projection(embeddings, method="umap") - - # Verify PCA was called + with import_without( + "semantica.visualization.embedding_visualizer", "umap" + ) as module: + with plotly_doubles(module), patch.object(module, "PCA") as mock_pca_class: + mock_pca_class.return_value.fit_transform.return_value = np.zeros((4, 2)) + + viz = module.EmbeddingVisualizer() + embeddings = np.array([[0, 1, 2], [1, 0, 3], [0, 0, 0], [1, 1, 1]]) + viz.visualize_2d_projection(embeddings, method="umap") + mock_pca_class.assert_called() def test_ontology_visualizer_without_graphviz(self): """Test OntologyVisualizer behavior when graphviz is missing.""" - # Ensure graphviz is missing - with patch.dict(sys.modules, {'graphviz': None}): - from semantica.visualization.ontology_visualizer import OntologyVisualizer, ProcessingError - - viz = OntologyVisualizer() + with import_without( + "semantica.visualization.ontology_visualizer", "graphviz" + ) as module: + viz = module.OntologyVisualizer() ontology = { "classes": [ {"name": "A", "label": "A"}, - {"name": "B", "label": "B", "parent": "A"} + {"name": "B", "label": "B", "parent": "A"}, ] } - - with self.assertRaises(ProcessingError) as cm: + + with self.assertRaises(module.ProcessingError) as cm: viz.visualize_hierarchy(ontology, output="dot", file_path="test.dot") - + self.assertIn("Graphviz is required for DOT export", str(cm.exception)) def test_analytics_visualizer_without_plotly(self): """Test AnalyticsVisualizer behavior when plotly is missing.""" - with patch.dict(sys.modules, {'plotly': None, 'plotly.express': None, 'plotly.graph_objects': None}): - from semantica.visualization.analytics_visualizer import AnalyticsVisualizer, ProcessingError - - # Need to ensure numpy is available for init (it's imported at top level) - # But we are testing plotly missing. - - viz = AnalyticsVisualizer() - - with self.assertRaises(ProcessingError) as cm: - viz.visualize_centrality_rankings({"node1": 1.0}) - - self.assertIn("Plotly is required", str(cm.exception)) + with import_without( + "semantica.visualization.analytics_visualizer", + "plotly", + "plotly.express", + "plotly.graph_objects", + ) as module: + viz = module.AnalyticsVisualizer() - def test_analytics_visualizer_without_plotly(self): - """Test AnalyticsVisualizer behavior when plotly is missing.""" - with patch.dict(sys.modules, {'plotly': None, 'plotly.express': None, 'plotly.graph_objects': None}): - from semantica.visualization.analytics_visualizer import AnalyticsVisualizer, ProcessingError - - viz = AnalyticsVisualizer() - - with self.assertRaises(ProcessingError) as cm: + with self.assertRaises(module.ProcessingError) as cm: viz.visualize_centrality_rankings({}) - + self.assertIn("Plotly is required", str(cm.exception)) def test_semantic_network_visualizer_without_plotly(self): """Test SemanticNetworkVisualizer behavior when plotly is missing.""" - with patch.dict(sys.modules, {'plotly': None, 'plotly.express': None, 'plotly.graph_objects': None}): - from semantica.visualization.semantic_network_visualizer import SemanticNetworkVisualizer, ProcessingError - - viz = SemanticNetworkVisualizer() - - with self.assertRaises(ProcessingError) as cm: + with import_without( + "semantica.visualization.semantic_network_visualizer", + "plotly", + "plotly.express", + "plotly.graph_objects", + ) as module: + viz = module.SemanticNetworkVisualizer() + + with self.assertRaises(module.ProcessingError) as cm: viz.visualize_network({}) - + self.assertIn("Plotly is required", str(cm.exception)) def test_temporal_visualizer_without_plotly(self): """Test TemporalVisualizer behavior when plotly is missing.""" - with patch.dict(sys.modules, {'plotly': None, 'plotly.express': None, 'plotly.graph_objects': None}): - from semantica.visualization.temporal_visualizer import TemporalVisualizer, ProcessingError - - viz = TemporalVisualizer() - - with self.assertRaises(ProcessingError) as cm: + with import_without( + "semantica.visualization.temporal_visualizer", + "plotly", + "plotly.express", + "plotly.graph_objects", + ) as module: + viz = module.TemporalVisualizer() + + with self.assertRaises(module.ProcessingError) as cm: viz.visualize_timeline({"events": []}) - + self.assertIn("Plotly is required", str(cm.exception)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/visualization/test_visualization.py b/tests/visualization/test_visualization.py index c8288584..424caf0e 100644 --- a/tests/visualization/test_visualization.py +++ b/tests/visualization/test_visualization.py @@ -1,27 +1,5 @@ import unittest -from unittest.mock import MagicMock, patch, ANY -import sys -import types - -# Helper to create a mock package -def mock_package(name): - m = MagicMock() - m.__path__ = [] - sys.modules[name] = m - return m - -# Mock libraries before importing module under test -# We need to ensure matplotlib behaves like a package for seaborn -sys.modules['matplotlib'] = MagicMock() -sys.modules['matplotlib.colors'] = MagicMock() -sys.modules['matplotlib.pyplot'] = MagicMock() -sys.modules['matplotlib.patches'] = MagicMock() -sys.modules['plotly'] = MagicMock() -sys.modules['plotly.express'] = MagicMock() -sys.modules['plotly.graph_objects'] = MagicMock() -sys.modules['plotly.subplots'] = MagicMock() -sys.modules['graphviz'] = MagicMock() -sys.modules['seaborn'] = MagicMock() +from unittest.mock import MagicMock, patch from semantica.visualization.kg_visualizer import KGVisualizer from semantica.visualization.ontology_visualizer import OntologyVisualizer diff --git a/tests/visualization/test_visualization_advanced.py b/tests/visualization/test_visualization_advanced.py index 8d69bd63..555565ef 100644 --- a/tests/visualization/test_visualization_advanced.py +++ b/tests/visualization/test_visualization_advanced.py @@ -1,34 +1,25 @@ import unittest +from contextlib import ExitStack from unittest.mock import MagicMock, patch -import sys import numpy as np -# Mock heavy libraries before importing visualization modules -sys.modules['matplotlib'] = MagicMock() -sys.modules['matplotlib.pyplot'] = MagicMock() -sys.modules['matplotlib.colors'] = MagicMock() -sys.modules['matplotlib.patches'] = MagicMock() -sys.modules['plotly'] = MagicMock() -sys.modules['plotly.express'] = MagicMock() -sys.modules['plotly.graph_objects'] = MagicMock() -sys.modules['plotly.subplots'] = MagicMock() -sys.modules['seaborn'] = MagicMock() -sys.modules['umap'] = MagicMock() -sys.modules['sklearn'] = MagicMock() -sys.modules['sklearn.decomposition'] = MagicMock() -sys.modules['sklearn.manifold'] = MagicMock() - +from semantica.visualization import analytics_visualizer, embedding_visualizer from semantica.visualization.analytics_visualizer import AnalyticsVisualizer from semantica.visualization.embedding_visualizer import EmbeddingVisualizer from semantica.visualization.utils.color_schemes import ColorScheme +from tests.visualization._plotly_doubles import plotly_doubles class TestVisualizationAdvanced(unittest.TestCase): def setUp(self): self.mock_logger = MagicMock() self.mock_tracker = MagicMock() - + + stack = ExitStack() + self.addCleanup(stack.close) + stack.enter_context(plotly_doubles(analytics_visualizer, embedding_visualizer)) + self.patchers = [ patch('semantica.visualization.analytics_visualizer.get_logger', return_value=self.mock_logger), patch('semantica.visualization.analytics_visualizer.get_progress_tracker', return_value=self.mock_tracker), @@ -53,22 +44,17 @@ class TestVisualizationAdvanced(unittest.TestCase): viz = AnalyticsVisualizer() centrality = {"n1": 0.5, "n2": 0.3} - # Access the mock that was injected - import plotly.graph_objects as go - # Reset mock to ensure clean state - go.Bar.reset_mock() - - viz.visualize_centrality_rankings(centrality, output="interactive") - go.Bar.assert_called() + with ( + patch('semantica.visualization.analytics_visualizer.go.Bar') as mock_bar, + patch('semantica.visualization.analytics_visualizer.go.Figure'), + ): + viz.visualize_centrality_rankings(centrality, output="interactive") + mock_bar.assert_called() def test_visualize_community_structure(self): viz = AnalyticsVisualizer() if hasattr(viz, 'visualize_community_structure'): - import plotly.graph_objects as go - # Reset mocks - go.Figure.reset_mock() - graph = MagicMock() communities = {"c1": ["n1", "n2"]} @@ -89,8 +75,6 @@ class TestVisualizationAdvanced(unittest.TestCase): viz = EmbeddingVisualizer() embeddings = np.random.rand(10, 128) - import plotly.graph_objects as go - # Mock UMAP/TSNE/PCA with patch('semantica.visualization.embedding_visualizer.umap') as mock_umap, \ patch('semantica.visualization.embedding_visualizer.TSNE') as mock_tsne, \ @@ -116,12 +100,13 @@ class TestVisualizationAdvanced(unittest.TestCase): viz = EmbeddingVisualizer() embeddings = np.random.rand(5, 5) - import plotly.graph_objects as go - go.Heatmap.reset_mock() - if hasattr(viz, 'visualize_similarity_heatmap'): - viz.visualize_similarity_heatmap(embeddings) - go.Heatmap.assert_called() + with ( + patch('semantica.visualization.embedding_visualizer.go.Heatmap') as mock_heatmap, + patch('semantica.visualization.embedding_visualizer.go.Figure'), + ): + viz.visualize_similarity_heatmap(embeddings) + mock_heatmap.assert_called() if __name__ == '__main__': unittest.main() diff --git a/tests/visualization/test_visualization_comprehensive.py b/tests/visualization/test_visualization_comprehensive.py index 37db07e8..2c3d7577 100644 --- a/tests/visualization/test_visualization_comprehensive.py +++ b/tests/visualization/test_visualization_comprehensive.py @@ -1,26 +1,9 @@ import unittest from unittest.mock import MagicMock, patch -import sys import numpy as np from pathlib import Path import pytest -# Mock heavy libraries before importing visualization modules -sys.modules['matplotlib'] = MagicMock() -sys.modules['matplotlib.pyplot'] = MagicMock() -sys.modules['matplotlib.colors'] = MagicMock() -sys.modules['matplotlib.patches'] = MagicMock() -sys.modules['plotly'] = MagicMock() -sys.modules['plotly.express'] = MagicMock() -sys.modules['plotly.graph_objects'] = MagicMock() -sys.modules['plotly.subplots'] = MagicMock() -sys.modules['seaborn'] = MagicMock() -sys.modules['umap'] = MagicMock() -sys.modules['sklearn'] = MagicMock() -sys.modules['sklearn.decomposition'] = MagicMock() -sys.modules['sklearn.manifold'] = MagicMock() -sys.modules['networkx'] = MagicMock() -sys.modules['graphviz'] = MagicMock() # Import visualizers from semantica.visualization.kg_visualizer import KGVisualizer @@ -52,24 +35,24 @@ class TestVisualizationComprehensive(unittest.TestCase): patch('semantica.visualization.analytics_visualizer.get_progress_tracker', return_value=self.mock_tracker), patch('semantica.visualization.temporal_visualizer.get_logger', return_value=self.mock_logger), patch('semantica.visualization.temporal_visualizer.get_progress_tracker', return_value=self.mock_tracker), - # Mock Layouts - patch('semantica.visualization.kg_visualizer.ForceDirectedLayout', MagicMock()), - patch('semantica.visualization.kg_visualizer.HierarchicalLayout', MagicMock()), - patch('semantica.visualization.kg_visualizer.CircularLayout', MagicMock()), - patch('semantica.visualization.ontology_visualizer.HierarchicalLayout', MagicMock()), - patch('semantica.visualization.semantic_network_visualizer.ForceDirectedLayout', MagicMock()), + patch('semantica.visualization.kg_visualizer.go', MagicMock()), + patch('semantica.visualization.kg_visualizer.px', MagicMock()), + patch('semantica.visualization.ontology_visualizer.go', MagicMock()), + patch('semantica.visualization.ontology_visualizer.make_subplots', MagicMock()), + patch('semantica.visualization.embedding_visualizer.go', MagicMock()), + patch('semantica.visualization.embedding_visualizer.px', MagicMock()), + patch('semantica.visualization.semantic_network_visualizer.go', MagicMock()), + patch('semantica.visualization.semantic_network_visualizer.px', MagicMock()), + patch('semantica.visualization.analytics_visualizer.go', MagicMock()), + patch('semantica.visualization.analytics_visualizer.px', MagicMock()), + patch('semantica.visualization.analytics_visualizer.make_subplots', MagicMock()), + patch('semantica.visualization.temporal_visualizer.go', MagicMock()), + patch('semantica.visualization.temporal_visualizer.px', MagicMock()), ] for p in self.patchers: p.start() - # Reset plotly mocks - import plotly.graph_objects as go - import plotly.express as px - go.Figure.reset_mock() - px.bar.reset_mock() - px.scatter.reset_mock() - def tearDown(self): for p in self.patchers: p.stop() @@ -210,8 +193,8 @@ class TestVisualizationComprehensive(unittest.TestCase): embeddings = np.random.rand(10, 10) # Test visualize_2d_projection (mock UMAP/PCA) - with patch('semantica.visualization.embedding_visualizer.umap.UMAP') as MockUMAP: - MockUMAP.return_value.fit_transform.return_value = np.random.rand(10, 2) + with patch('semantica.visualization.embedding_visualizer.umap', MagicMock()) as mock_umap: + mock_umap.UMAP.return_value.fit_transform.return_value = np.random.rand(10, 2) viz.visualize_2d_projection(embeddings) # Test visualize_similarity_heatmap @@ -219,8 +202,8 @@ class TestVisualizationComprehensive(unittest.TestCase): # Test visualize_clustering clusters = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] - with patch('semantica.visualization.embedding_visualizer.umap.UMAP') as MockUMAP: - MockUMAP.return_value.fit_transform.return_value = np.random.rand(10, 2) + with patch('semantica.visualization.embedding_visualizer.umap', MagicMock()) as mock_umap: + mock_umap.UMAP.return_value.fit_transform.return_value = np.random.rand(10, 2) viz.visualize_clustering(embeddings, clusters) if __name__ == '__main__':