diff --git a/test/conftest.py b/test/conftest.py new file mode 100644 index 0000000..1e51aca --- /dev/null +++ b/test/conftest.py @@ -0,0 +1,37 @@ +import sys +from unittest.mock import MagicMock + +import sys +from unittest.mock import MagicMock + +def pytest_configure(config): + """ + This hook runs at the start of the pytest session, before any tests are + collected. It mocks heavy or unavailable modules to prevent ImportErrors. + """ + # --- Mock spade and spade-bdi --- + mock_spade = MagicMock() + mock_spade.agent = MagicMock() + mock_spade.behaviour = MagicMock() + mock_spade_bdi = MagicMock() + mock_spade_bdi.bdi = MagicMock() + + mock_spade.agent.Message = MagicMock() + mock_spade.behaviour.CyclicBehaviour = type('CyclicBehaviour', (object,), {}) + mock_spade_bdi.bdi.BDIAgent = type('BDIAgent', (object,), {}) + + sys.modules['spade'] = mock_spade + sys.modules['spade.agent'] = mock_spade.agent + sys.modules['spade.behaviour'] = mock_spade.behaviour + sys.modules['spade_bdi'] = mock_spade_bdi + sys.modules['spade_bdi.bdi'] = mock_spade_bdi.bdi + + # --- Mock the config module to prevent Pydantic ImportError --- + mock_config_module = MagicMock() + + # The code under test does `from ... import settings`, so our mock module + # must have a `settings` attribute. We'll make it a MagicMock so we can + # configure it later in our tests using mocker.patch. + mock_config_module.settings = MagicMock() + + sys.modules['control_backend.core.config'] = mock_config_module diff --git a/test/unit/agents/bdi/behaviours/test_belief_setter.py b/test/unit/agents/bdi/behaviours/test_belief_setter.py index 471d310..8932834 100644 --- a/test/unit/agents/bdi/behaviours/test_belief_setter.py +++ b/test/unit/agents/bdi/behaviours/test_belief_setter.py @@ -1,10 +1,8 @@ -import asyncio import json import logging from unittest.mock import MagicMock, AsyncMock, call import pytest -from spade.agent import Message from control_backend.agents.bdi.behaviours.belief_setter import BeliefSetter @@ -40,6 +38,15 @@ def belief_setter(mock_agent, mocker): return setter +def create_mock_message(sender_node: str, body: str, thread: str) -> MagicMock: + """Helper function to create a configured mock message.""" + msg = MagicMock() + msg.sender.node = sender_node # MagicMock automatically creates nested mocks + msg.body = body + msg.thread = thread + return msg + + @pytest.mark.asyncio async def test_run_no_message_received(belief_setter, mocker): """ @@ -62,7 +69,7 @@ async def test_run_message_received(belief_setter, mocker): Test that when a message is received, _process_message is called. """ # Arrange - msg = Message(to="bdi_agent@test") + msg = MagicMock(); belief_setter.receive.return_value = msg mocker.patch.object(belief_setter, "_process_message") @@ -78,7 +85,7 @@ def test_process_message_from_belief_collector(belief_setter, mocker): Test processing a message from the correct belief collector agent. """ # Arrange - msg = Message(to="bdi_agent@test", sender=COLLECTOR_AGENT_JID) + msg = create_mock_message(sender_node=COLLECTOR_AGENT_NAME, body="", thread="") mock_process_belief = mocker.patch.object(belief_setter, "_process_belief_message") # Act @@ -93,7 +100,7 @@ def test_process_message_from_other_agent(belief_setter, mocker): Test that messages from other agents are ignored. """ # Arrange - msg = Message(to="bdi_agent@test", sender="other_agent@test") + msg = create_mock_message(sender_node="other_agent", body="", thread="") mock_process_belief = mocker.patch.object(belief_setter, "_process_belief_message") # Act @@ -112,9 +119,8 @@ def test_process_belief_message_valid_json(belief_setter, mocker): "is_hot": [["kitchen"]], "is_clean": [["kitchen"], ["bathroom"]] } - msg = Message( - to="bdi_agent@test", - sender=COLLECTOR_AGENT_JID, + msg = create_mock_message( + sender_node=COLLECTOR_AGENT_JID, body=json.dumps(beliefs_payload), thread="beliefs" ) @@ -132,9 +138,8 @@ def test_process_belief_message_invalid_json(belief_setter, mocker, caplog): Test that a message with invalid JSON is handled gracefully and an error is logged. """ # Arrange - msg = Message( - to="bdi_agent@test", - sender=COLLECTOR_AGENT_JID, + msg = create_mock_message( + sender_node=COLLECTOR_AGENT_JID, body="this is not a json string", thread="beliefs" ) @@ -154,9 +159,8 @@ def test_process_belief_message_wrong_thread(belief_setter, mocker): Test that a message with an incorrect thread is ignored. """ # Arrange - msg = Message( - to="bdi_agent@test", - sender=COLLECTOR_AGENT_JID, + msg = create_mock_message( + sender_node=COLLECTOR_AGENT_JID, body='{"some": "data"}', thread="not_beliefs" ) @@ -173,9 +177,8 @@ def test_process_belief_message_empty_body(belief_setter, mocker): Test that a message with an empty body is ignored. """ # Arrange - msg = Message( - to="bdi_agent@test", - sender=COLLECTOR_AGENT_JID, + msg = create_mock_message( + sender_node=COLLECTOR_AGENT_JID, body="", thread="beliefs" )