refactor: change test folder structure, rename functions to account for (non)changing behaviours and clarity
ref: N25B-257
This commit is contained in:
@@ -29,7 +29,7 @@ class ActSpeechAgent(BaseAgent):
|
||||
self.address = address
|
||||
self.bind = bind
|
||||
|
||||
class SendCommandsBehaviour(CyclicBehaviour):
|
||||
class SendZMQCommandsBehaviour(CyclicBehaviour):
|
||||
"""Behaviour for sending commands received from the UI."""
|
||||
|
||||
async def run(self):
|
||||
@@ -50,7 +50,7 @@ class ActSpeechAgent(BaseAgent):
|
||||
except Exception as e:
|
||||
self.agent.logger.error("Error processing message: %s", e)
|
||||
|
||||
class SendPythonCommandsBehaviour(CyclicBehaviour):
|
||||
class SendSpadeCommandsBehaviour(CyclicBehaviour):
|
||||
"""Behaviour for sending commands received from other Python agents."""
|
||||
|
||||
async def run(self):
|
||||
@@ -83,8 +83,8 @@ class ActSpeechAgent(BaseAgent):
|
||||
self.subsocket.setsockopt(zmq.SUBSCRIBE, b"command")
|
||||
|
||||
# Add behaviour to our agent
|
||||
commands_behaviour = self.SendCommandsBehaviour()
|
||||
commands_behaviour = self.SendZMQCommandsBehaviour()
|
||||
self.add_behaviour(commands_behaviour)
|
||||
self.add_behaviour(self.SendPythonCommandsBehaviour())
|
||||
self.add_behaviour(self.SendSpadeCommandsBehaviour())
|
||||
|
||||
self.logger.info("Finished setting up %s", self.jid)
|
||||
|
||||
@@ -7,7 +7,7 @@ from spade.behaviour import CyclicBehaviour
|
||||
from control_backend.core.config import settings
|
||||
|
||||
|
||||
class ContinuousBeliefCollector(CyclicBehaviour):
|
||||
class BelCollectorBehaviour(CyclicBehaviour):
|
||||
"""
|
||||
Continuously collects beliefs/emotions from extractor agents:
|
||||
Then we send a unified belief packet to the BDI agent.
|
||||
@@ -1,11 +1,11 @@
|
||||
from control_backend.agents.base import BaseAgent
|
||||
|
||||
from .behaviours.continuous_collect import ContinuousBeliefCollector
|
||||
from .behaviours.bel_collector_behaviour import BelCollectorBehaviour
|
||||
|
||||
|
||||
class BDIBeliefCollectorAgent(BaseAgent):
|
||||
async def setup(self):
|
||||
self.logger.info("BDIBeliefCollectorAgent starting (%s)", self.jid)
|
||||
# Attach the continuous collector behaviour (listens and forwards to BDI)
|
||||
self.add_behaviour(ContinuousBeliefCollector())
|
||||
self.add_behaviour(BelCollectorBehaviour())
|
||||
self.logger.info("BDIBeliefCollectorAgent ready.")
|
||||
|
||||
@@ -7,7 +7,7 @@ from spade_bdi.bdi import BDIAgent
|
||||
|
||||
from control_backend.core.config import settings
|
||||
|
||||
from .behaviours.belief_setter import BeliefSetterBehaviour
|
||||
from .behaviours.belief_setter_behaviour import BeliefSetterBehaviour
|
||||
from .behaviours.receive_llm_resp_behaviour import ReceiveLLMResponseBehaviour
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from control_backend.agents.base import BaseAgent
|
||||
|
||||
from .behaviours.text_belief_extractor import BeliefFromText
|
||||
from .behaviours.bdi_text_belief_behaviour import BDITextBeliefBehaviour
|
||||
|
||||
|
||||
class BDITextBeliefAgent(BaseAgent):
|
||||
async def setup(self):
|
||||
self.add_behaviour(BeliefFromText())
|
||||
self.add_behaviour(BDITextBeliefBehaviour())
|
||||
|
||||
@@ -7,7 +7,7 @@ from spade.message import Message
|
||||
from control_backend.core.config import settings
|
||||
|
||||
|
||||
class BeliefFromText(CyclicBehaviour):
|
||||
class BDITextBeliefBehaviour(CyclicBehaviour):
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# TODO: LLM prompt nog hardcoded
|
||||
@@ -114,7 +114,7 @@ async def lifespan(app: FastAPI):
|
||||
"password": settings.agent_settings.bdi_belief_collector_agent_name,
|
||||
},
|
||||
),
|
||||
"TBeliefExtractor": (
|
||||
"BDITextBeliefAgent": (
|
||||
BDITextBeliefAgent,
|
||||
{
|
||||
"name": settings.agent_settings.bdi_text_belief_agent_name,
|
||||
|
||||
@@ -34,7 +34,7 @@ async def test_setup_bind(zmq_context, mocker):
|
||||
fake_socket.setsockopt.assert_any_call(zmq.SUBSCRIBE, b"command")
|
||||
|
||||
# Ensure behaviour attached
|
||||
assert any(isinstance(b, agent.SendCommandsBehaviour) for b in agent.behaviours)
|
||||
assert any(isinstance(b, agent.SendZMQCommandsBehaviour) for b in agent.behaviours)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -66,7 +66,7 @@ async def test_send_commands_behaviour_valid_message():
|
||||
agent.subsocket = fake_socket
|
||||
agent.pubsocket = fake_socket
|
||||
|
||||
behaviour = agent.SendCommandsBehaviour()
|
||||
behaviour = agent.SendZMQCommandsBehaviour()
|
||||
behaviour.agent = agent
|
||||
|
||||
with patch(
|
||||
@@ -92,7 +92,7 @@ async def test_send_commands_behaviour_invalid_message(caplog):
|
||||
agent.subsocket = fake_socket
|
||||
agent.pubsocket = fake_socket
|
||||
|
||||
behaviour = agent.SendCommandsBehaviour()
|
||||
behaviour = agent.SendZMQCommandsBehaviour()
|
||||
behaviour.agent = agent
|
||||
|
||||
await behaviour.run()
|
||||
@@ -3,8 +3,8 @@ from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from control_backend.agents.bdi_agents.bdi_belief_collector_agent.behaviours.continuous_collect import ( # noqa: E501
|
||||
ContinuousBeliefCollector,
|
||||
from control_backend.agents.bdi_agents.bdi_belief_collector_agent.behaviours.bel_collector_behaviour import ( # noqa: E501
|
||||
BelCollectorBehaviour,
|
||||
)
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ def mock_agent(mocker):
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def continuous_collector(mock_agent, mocker):
|
||||
"""Fixture to create an instance of ContinuousBeliefCollector with a mocked agent."""
|
||||
def bel_collector_behaviouror(mock_agent, mocker):
|
||||
"""Fixture to create an instance of BelCollectorBehaviour with a mocked agent."""
|
||||
# Patch asyncio.sleep to prevent tests from actually waiting
|
||||
mocker.patch("asyncio.sleep", return_value=None)
|
||||
|
||||
collector = ContinuousBeliefCollector()
|
||||
collector = BelCollectorBehaviour()
|
||||
collector.agent = mock_agent
|
||||
# Mock the receive method, we will control its return value in each test
|
||||
collector.receive = AsyncMock()
|
||||
@@ -38,64 +38,64 @@ def continuous_collector(mock_agent, mocker):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_message_received(continuous_collector, mocker):
|
||||
async def test_run_message_received(bel_collector_behaviouror, mocker):
|
||||
"""
|
||||
Test that when a message is received, _process_message is called with that message.
|
||||
"""
|
||||
# Arrange
|
||||
mock_msg = MagicMock()
|
||||
continuous_collector.receive.return_value = mock_msg
|
||||
mocker.patch.object(continuous_collector, "_process_message")
|
||||
bel_collector_behaviouror.receive.return_value = mock_msg
|
||||
mocker.patch.object(bel_collector_behaviouror, "_process_message")
|
||||
|
||||
# Act
|
||||
await continuous_collector.run()
|
||||
await bel_collector_behaviouror.run()
|
||||
|
||||
# Assert
|
||||
continuous_collector._process_message.assert_awaited_once_with(mock_msg)
|
||||
bel_collector_behaviouror._process_message.assert_awaited_once_with(mock_msg)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_routes_to_handle_belief_text_by_type(continuous_collector, mocker):
|
||||
async def test_routes_to_handle_belief_text_by_type(bel_collector_behaviouror, mocker):
|
||||
msg = create_mock_message(
|
||||
"anyone",
|
||||
json.dumps({"type": "belief_extraction_text", "beliefs": {"user_said": [["hi"]]}}),
|
||||
)
|
||||
spy = mocker.patch.object(continuous_collector, "_handle_belief_text", new=AsyncMock())
|
||||
await continuous_collector._process_message(msg)
|
||||
spy = mocker.patch.object(bel_collector_behaviouror, "_handle_belief_text", new=AsyncMock())
|
||||
await bel_collector_behaviouror._process_message(msg)
|
||||
spy.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_routes_to_handle_belief_text_by_sender(continuous_collector, mocker):
|
||||
async def test_routes_to_handle_belief_text_by_sender(bel_collector_behaviouror, mocker):
|
||||
msg = create_mock_message(
|
||||
"bel_text_agent_mock", json.dumps({"beliefs": {"user_said": [["hi"]]}})
|
||||
)
|
||||
spy = mocker.patch.object(continuous_collector, "_handle_belief_text", new=AsyncMock())
|
||||
await continuous_collector._process_message(msg)
|
||||
spy = mocker.patch.object(bel_collector_behaviouror, "_handle_belief_text", new=AsyncMock())
|
||||
await bel_collector_behaviouror._process_message(msg)
|
||||
spy.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_routes_to_handle_emo_text(continuous_collector, mocker):
|
||||
async def test_routes_to_handle_emo_text(bel_collector_behaviouror, mocker):
|
||||
msg = create_mock_message("anyone", json.dumps({"type": "emotion_extraction_text"}))
|
||||
spy = mocker.patch.object(continuous_collector, "_handle_emo_text", new=AsyncMock())
|
||||
await continuous_collector._process_message(msg)
|
||||
spy = mocker.patch.object(bel_collector_behaviouror, "_handle_emo_text", new=AsyncMock())
|
||||
await bel_collector_behaviouror._process_message(msg)
|
||||
spy.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_belief_text_happy_path_sends(continuous_collector, mocker):
|
||||
async def test_belief_text_happy_path_sends(bel_collector_behaviouror, mocker):
|
||||
payload = {"type": "belief_extraction_text", "beliefs": {"user_said": ["hello test", "No"]}}
|
||||
continuous_collector.send = AsyncMock()
|
||||
await continuous_collector._handle_belief_text(payload, "bel_text_agent_mock")
|
||||
bel_collector_behaviouror.send = AsyncMock()
|
||||
await bel_collector_behaviouror._handle_belief_text(payload, "bel_text_agent_mock")
|
||||
|
||||
# make sure we attempted a send
|
||||
continuous_collector.send.assert_awaited_once()
|
||||
bel_collector_behaviouror.send.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_belief_text_coerces_non_strings(continuous_collector, mocker):
|
||||
async def test_belief_text_coerces_non_strings(bel_collector_behaviouror, mocker):
|
||||
payload = {"type": "belief_extraction_text", "beliefs": {"user_said": [["hi", 123]]}}
|
||||
continuous_collector.send = AsyncMock()
|
||||
await continuous_collector._handle_belief_text(payload, "origin")
|
||||
continuous_collector.send.assert_awaited_once()
|
||||
bel_collector_behaviouror.send = AsyncMock()
|
||||
await bel_collector_behaviouror._handle_belief_text(payload, "origin")
|
||||
bel_collector_behaviouror.send.assert_awaited_once()
|
||||
@@ -4,7 +4,7 @@ from unittest.mock import AsyncMock, MagicMock, call
|
||||
|
||||
import pytest
|
||||
|
||||
from control_backend.agents.bdi_agents.bdi_core_agent.behaviours.belief_setter import (
|
||||
from control_backend.agents.bdi_agents.bdi_core_agent.behaviours.belief_setter_behaviour import (
|
||||
BeliefSetterBehaviour,
|
||||
)
|
||||
|
||||
@@ -23,12 +23,12 @@ def mock_agent(mocker):
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def belief_setter(mock_agent, mocker):
|
||||
def belief_setter_behaviour(mock_agent, mocker):
|
||||
"""Fixture to create an instance of BeliefSetterBehaviour with a mocked agent."""
|
||||
# Patch the settings to use a predictable agent name
|
||||
mocker.patch(
|
||||
"control_backend.agents.bdi_agents.bdi_core_agent."
|
||||
"behaviours.belief_setter.settings.agent_settings.bdi_belief_collector_agent_name",
|
||||
"behaviours.belief_setter_behaviour.settings.agent_settings.bdi_belief_collector_agent_name",
|
||||
COLLECTOR_AGENT_NAME,
|
||||
)
|
||||
|
||||
@@ -49,53 +49,53 @@ def create_mock_message(sender_node: str, body: str, thread: str) -> MagicMock:
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_message_received(belief_setter, mocker):
|
||||
async def test_run_message_received(belief_setter_behaviour, mocker):
|
||||
"""
|
||||
Test that when a message is received, _process_message is called.
|
||||
"""
|
||||
# Arrange
|
||||
msg = MagicMock()
|
||||
belief_setter.receive.return_value = msg
|
||||
mocker.patch.object(belief_setter, "_process_message")
|
||||
belief_setter_behaviour.receive.return_value = msg
|
||||
mocker.patch.object(belief_setter_behaviour, "_process_message")
|
||||
|
||||
# Act
|
||||
await belief_setter.run()
|
||||
await belief_setter_behaviour.run()
|
||||
|
||||
# Assert
|
||||
belief_setter._process_message.assert_called_once_with(msg)
|
||||
belief_setter_behaviour._process_message.assert_called_once_with(msg)
|
||||
|
||||
|
||||
def test_process_message_from_bdi_belief_collector_agent(belief_setter, mocker):
|
||||
def test_process_message_from_bdi_belief_collector_agent(belief_setter_behaviour, mocker):
|
||||
"""
|
||||
Test processing a message from the correct belief collector agent.
|
||||
"""
|
||||
# Arrange
|
||||
msg = create_mock_message(sender_node=COLLECTOR_AGENT_NAME, body="", thread="")
|
||||
mock_process_belief = mocker.patch.object(belief_setter, "_process_belief_message")
|
||||
mock_process_belief = mocker.patch.object(belief_setter_behaviour, "_process_belief_message")
|
||||
|
||||
# Act
|
||||
belief_setter._process_message(msg)
|
||||
belief_setter_behaviour._process_message(msg)
|
||||
|
||||
# Assert
|
||||
mock_process_belief.assert_called_once_with(msg)
|
||||
|
||||
|
||||
def test_process_message_from_other_agent(belief_setter, mocker):
|
||||
def test_process_message_from_other_agent(belief_setter_behaviour, mocker):
|
||||
"""
|
||||
Test that messages from other agents are ignored.
|
||||
"""
|
||||
# Arrange
|
||||
msg = create_mock_message(sender_node="other_agent", body="", thread="")
|
||||
mock_process_belief = mocker.patch.object(belief_setter, "_process_belief_message")
|
||||
mock_process_belief = mocker.patch.object(belief_setter_behaviour, "_process_belief_message")
|
||||
|
||||
# Act
|
||||
belief_setter._process_message(msg)
|
||||
belief_setter_behaviour._process_message(msg)
|
||||
|
||||
# Assert
|
||||
mock_process_belief.assert_not_called()
|
||||
|
||||
|
||||
def test_process_belief_message_valid_json(belief_setter, mocker):
|
||||
def test_process_belief_message_valid_json(belief_setter_behaviour, mocker):
|
||||
"""
|
||||
Test processing a valid belief message with correct thread and JSON body.
|
||||
"""
|
||||
@@ -104,16 +104,16 @@ def test_process_belief_message_valid_json(belief_setter, mocker):
|
||||
msg = create_mock_message(
|
||||
sender_node=COLLECTOR_AGENT_JID, body=json.dumps(beliefs_payload), thread="beliefs"
|
||||
)
|
||||
mock_set_beliefs = mocker.patch.object(belief_setter, "_set_beliefs")
|
||||
mock_set_beliefs = mocker.patch.object(belief_setter_behaviour, "_set_beliefs")
|
||||
|
||||
# Act
|
||||
belief_setter._process_belief_message(msg)
|
||||
belief_setter_behaviour._process_belief_message(msg)
|
||||
|
||||
# Assert
|
||||
mock_set_beliefs.assert_called_once_with(beliefs_payload)
|
||||
|
||||
|
||||
def test_process_belief_message_invalid_json(belief_setter, mocker, caplog):
|
||||
def test_process_belief_message_invalid_json(belief_setter_behaviour, mocker, caplog):
|
||||
"""
|
||||
Test that a message with invalid JSON is handled gracefully and an error is logged.
|
||||
"""
|
||||
@@ -121,16 +121,16 @@ def test_process_belief_message_invalid_json(belief_setter, mocker, caplog):
|
||||
msg = create_mock_message(
|
||||
sender_node=COLLECTOR_AGENT_JID, body="this is not a json string", thread="beliefs"
|
||||
)
|
||||
mock_set_beliefs = mocker.patch.object(belief_setter, "_set_beliefs")
|
||||
mock_set_beliefs = mocker.patch.object(belief_setter_behaviour, "_set_beliefs")
|
||||
|
||||
# Act
|
||||
belief_setter._process_belief_message(msg)
|
||||
belief_setter_behaviour._process_belief_message(msg)
|
||||
|
||||
# Assert
|
||||
mock_set_beliefs.assert_not_called()
|
||||
|
||||
|
||||
def test_process_belief_message_wrong_thread(belief_setter, mocker):
|
||||
def test_process_belief_message_wrong_thread(belief_setter_behaviour, mocker):
|
||||
"""
|
||||
Test that a message with an incorrect thread is ignored.
|
||||
"""
|
||||
@@ -138,31 +138,31 @@ def test_process_belief_message_wrong_thread(belief_setter, mocker):
|
||||
msg = create_mock_message(
|
||||
sender_node=COLLECTOR_AGENT_JID, body='{"some": "data"}', thread="not_beliefs"
|
||||
)
|
||||
mock_set_beliefs = mocker.patch.object(belief_setter, "_set_beliefs")
|
||||
mock_set_beliefs = mocker.patch.object(belief_setter_behaviour, "_set_beliefs")
|
||||
|
||||
# Act
|
||||
belief_setter._process_belief_message(msg)
|
||||
belief_setter_behaviour._process_belief_message(msg)
|
||||
|
||||
# Assert
|
||||
mock_set_beliefs.assert_not_called()
|
||||
|
||||
|
||||
def test_process_belief_message_empty_body(belief_setter, mocker):
|
||||
def test_process_belief_message_empty_body(belief_setter_behaviour, mocker):
|
||||
"""
|
||||
Test that a message with an empty body is ignored.
|
||||
"""
|
||||
# Arrange
|
||||
msg = create_mock_message(sender_node=COLLECTOR_AGENT_JID, body="", thread="beliefs")
|
||||
mock_set_beliefs = mocker.patch.object(belief_setter, "_set_beliefs")
|
||||
mock_set_beliefs = mocker.patch.object(belief_setter_behaviour, "_set_beliefs")
|
||||
|
||||
# Act
|
||||
belief_setter._process_belief_message(msg)
|
||||
belief_setter_behaviour._process_belief_message(msg)
|
||||
|
||||
# Assert
|
||||
mock_set_beliefs.assert_not_called()
|
||||
|
||||
|
||||
def test_set_beliefs_success(belief_setter, mock_agent, caplog):
|
||||
def test_set_beliefs_success(belief_setter_behaviour, mock_agent, caplog):
|
||||
"""
|
||||
Test that beliefs are correctly set on the agent's BDI.
|
||||
"""
|
||||
@@ -174,7 +174,7 @@ def test_set_beliefs_success(belief_setter, mock_agent, caplog):
|
||||
|
||||
# Act
|
||||
with caplog.at_level(logging.INFO):
|
||||
belief_setter._set_beliefs(beliefs_to_set)
|
||||
belief_setter_behaviour._set_beliefs(beliefs_to_set)
|
||||
|
||||
# Assert
|
||||
expected_calls = [
|
||||
@@ -185,18 +185,18 @@ def test_set_beliefs_success(belief_setter, mock_agent, caplog):
|
||||
assert mock_agent.bdi.set_belief.call_count == 2
|
||||
|
||||
|
||||
# def test_responded_unset(belief_setter, mock_agent):
|
||||
# def test_responded_unset(belief_setter_behaviour, mock_agent):
|
||||
# # Arrange
|
||||
# new_beliefs = {"user_said": ["message"]}
|
||||
#
|
||||
# # Act
|
||||
# belief_setter._set_beliefs(new_beliefs)
|
||||
# belief_setter_behaviour._set_beliefs(new_beliefs)
|
||||
#
|
||||
# # Assert
|
||||
# mock_agent.bdi.set_belief.assert_has_calls([call("user_said", "message")])
|
||||
# mock_agent.bdi.remove_belief.assert_has_calls([call("responded")])
|
||||
|
||||
# def test_set_beliefs_bdi_not_initialized(belief_setter, mock_agent, caplog):
|
||||
# def test_set_beliefs_bdi_not_initialized(belief_setter_behaviour, mock_agent, caplog):
|
||||
# """
|
||||
# Test that a warning is logged if the agent's BDI is not initialized.
|
||||
# """
|
||||
@@ -206,7 +206,7 @@ def test_set_beliefs_success(belief_setter, mock_agent, caplog):
|
||||
#
|
||||
# # Act
|
||||
# with caplog.at_level(logging.WARNING):
|
||||
# belief_setter._set_beliefs(beliefs_to_set)
|
||||
# belief_setter_behaviour._set_beliefs(beliefs_to_set)
|
||||
#
|
||||
# # Assert
|
||||
# assert "Cannot set beliefs, since agent's BDI is not yet initialized." in caplog.text
|
||||
@@ -4,8 +4,8 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
||||
import pytest
|
||||
from spade.message import Message
|
||||
|
||||
from control_backend.agents.bdi_agents.bdi_text_belief_agent.behaviours.text_belief_extractor import ( # noqa: E501, We can't shorten this import.
|
||||
BeliefFromText,
|
||||
from control_backend.agents.bdi_agents.bdi_text_belief_agent.behaviours.bdi_text_belief_behaviour import ( # noqa: E501, We can't shorten this import.
|
||||
BDITextBeliefBehaviour,
|
||||
)
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ def mock_settings():
|
||||
# Adjust 'control_backend.behaviours.belief_from_text.settings' to where
|
||||
# your behaviour file imports it from.
|
||||
with patch(
|
||||
"control_backend.agents.bdi_agents.bdi_text_belief_agent.behaviours.text_belief_extractor.settings",
|
||||
"control_backend.agents.bdi_agents.bdi_text_belief_agent.behaviours.bdi_text_belief_behaviour.settings",
|
||||
settings_mock,
|
||||
):
|
||||
yield settings_mock
|
||||
@@ -34,10 +34,10 @@ def mock_settings():
|
||||
@pytest.fixture
|
||||
def behavior(mock_settings):
|
||||
"""
|
||||
Creates an instance of the BeliefFromText behaviour and mocks its
|
||||
Creates an instance of the BDITextBeliefBehaviour behaviour and mocks its
|
||||
agent, logger, send, and receive methods.
|
||||
"""
|
||||
b = BeliefFromText()
|
||||
b = BDITextBeliefBehaviour()
|
||||
|
||||
b.agent = MagicMock()
|
||||
b.send = AsyncMock()
|
||||
Reference in New Issue
Block a user