fix: bypass pydantic validation for mocks in BaseAgentExecutor tests

After model_rebuild, BaseAgentExecutor rejects plain MagicMock for
typed fields. Construct with defaults then assign mocks post-init.
Also guard RuntimeState tests for environments where model_rebuild fails.
This commit is contained in:
Greyson LaLonde
2026-04-04 03:33:07 +08:00
parent 206259b537
commit a94c2bf786
3 changed files with 34 additions and 47 deletions

View File

@@ -523,33 +523,28 @@ class TestAgentScopeExtension:
def test_agent_save_extends_crew_root_scope(self) -> None:
"""Agent._save_to_memory extends crew's root_scope with agent info."""
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.agent_builder.base_agent_executor import (
BaseAgentExecutor,
)
from crewai.agents.parser import AgentFinish
from crewai.task import Task
from crewai.utilities.printer import Printer
mock_memory = MagicMock()
mock_memory.read_only = False
mock_memory.root_scope = "/crew/research-crew"
mock_memory.extract_memories.return_value = ["Fact A"]
mock_agent = MagicMock(spec=BaseAgent)
mock_agent = MagicMock()
mock_agent.memory = mock_memory
mock_agent._logger = MagicMock()
mock_agent.role = "Researcher"
mock_task = MagicMock(spec=Task)
mock_task = MagicMock()
mock_task.description = "Research task"
mock_task.expected_output = "Report"
executor = BaseAgentExecutor(
crew=None,
agent=mock_agent,
task=mock_task,
)
executor = BaseAgentExecutor()
executor.agent = mock_agent
executor.task = mock_task
executor._save_to_memory(AgentFinish(thought="", output="Result", text="Result"))
@@ -559,33 +554,28 @@ class TestAgentScopeExtension:
def test_agent_save_sanitizes_role(self) -> None:
"""Agent role with special chars is sanitized for scope path."""
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.agent_builder.base_agent_executor import (
BaseAgentExecutor,
)
from crewai.agents.parser import AgentFinish
from crewai.task import Task
from crewai.utilities.printer import Printer
mock_memory = MagicMock()
mock_memory.read_only = False
mock_memory.root_scope = "/crew/test"
mock_memory.extract_memories.return_value = ["Fact"]
mock_agent = MagicMock(spec=BaseAgent)
mock_agent = MagicMock()
mock_agent.memory = mock_memory
mock_agent._logger = MagicMock()
mock_agent.role = "Senior Research Analyst #1"
mock_task = MagicMock(spec=Task)
mock_task = MagicMock()
mock_task.description = "Task"
mock_task.expected_output = "Output"
executor = BaseAgentExecutor(
crew=None,
agent=mock_agent,
task=mock_task,
)
executor = BaseAgentExecutor()
executor.agent = mock_agent
executor.task = mock_task
executor._save_to_memory(AgentFinish(thought="", output="R", text="R"))
@@ -1087,32 +1077,28 @@ class TestAgentExecutorBackwardCompat:
def test_agent_executor_extends_root_scope_when_memory_has_one(self) -> None:
"""Agent executor extends root_scope when memory has one."""
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.agent_builder.base_agent_executor import (
BaseAgentExecutor,
)
from crewai.agents.parser import AgentFinish
from crewai.task import Task
mock_memory = MagicMock()
mock_memory.read_only = False
mock_memory.root_scope = "/crew/test" # Has root_scope
mock_memory.extract_memories.return_value = ["Fact A"]
mock_agent = MagicMock(spec=BaseAgent)
mock_agent = MagicMock()
mock_agent.memory = mock_memory
mock_agent._logger = MagicMock()
mock_agent.role = "Researcher"
mock_task = MagicMock(spec=Task)
mock_task = MagicMock()
mock_task.description = "Task"
mock_task.expected_output = "Output"
executor = BaseAgentExecutor(
crew=None,
agent=mock_agent,
task=mock_task,
)
executor = BaseAgentExecutor()
executor.agent = mock_agent
executor.task = mock_task
executor._save_to_memory(AgentFinish(thought="", output="R", text="R"))

View File

@@ -315,29 +315,25 @@ def test_memory_extract_memories_empty_content_returns_empty_list(tmp_path: Path
def test_executor_save_to_memory_calls_extract_then_remember_per_item() -> None:
"""_save_to_memory calls memory.extract_memories(raw) then memory.remember(m) for each."""
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.agent_builder.base_agent_executor import BaseAgentExecutor
from crewai.agents.parser import AgentFinish
from crewai.task import Task
mock_memory = MagicMock()
mock_memory.read_only = False
mock_memory.extract_memories.return_value = ["Fact A.", "Fact B."]
mock_agent = MagicMock(spec=BaseAgent)
mock_agent = MagicMock()
mock_agent.memory = mock_memory
mock_agent._logger = MagicMock()
mock_agent.role = "Researcher"
mock_task = MagicMock(spec=Task)
mock_task = MagicMock()
mock_task.description = "Do research"
mock_task.expected_output = "A report"
executor = BaseAgentExecutor(
crew=None,
agent=mock_agent,
task=mock_task,
)
executor = BaseAgentExecutor()
executor.agent = mock_agent
executor.task = mock_task
executor._save_to_memory(
AgentFinish(thought="", output="We found X and Y.", text="We found X and Y.")
)
@@ -351,28 +347,24 @@ def test_executor_save_to_memory_calls_extract_then_remember_per_item() -> None:
def test_executor_save_to_memory_skips_delegation_output() -> None:
"""_save_to_memory does nothing when output contains delegate action."""
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.agent_builder.base_agent_executor import BaseAgentExecutor
from crewai.agents.parser import AgentFinish
from crewai.task import Task
from crewai.utilities.string_utils import sanitize_tool_name
mock_memory = MagicMock()
mock_memory.read_only = False
mock_agent = MagicMock(spec=BaseAgent)
mock_agent = MagicMock()
mock_agent.memory = mock_memory
mock_agent._logger = MagicMock()
mock_task = MagicMock(spec=Task)
mock_task = MagicMock()
mock_task.description = "Task"
mock_task.expected_output = "Out"
delegate_text = f"Action: {sanitize_tool_name('Delegate work to coworker')}"
full_text = delegate_text + " rest"
executor = BaseAgentExecutor(
crew=None,
agent=mock_agent,
task=mock_task,
)
executor = BaseAgentExecutor()
executor.agent = mock_agent
executor.task = mock_task
executor._save_to_memory(
AgentFinish(thought="", output=full_text, text=full_text)
)

View File

@@ -342,6 +342,9 @@ class TestRuntimeStateIntegration:
def test_runtime_state_serializes_event_record(self):
from crewai import Agent, Crew, RuntimeState
if RuntimeState is None:
pytest.skip("RuntimeState unavailable (model_rebuild failed)")
agent = Agent(
role="test", goal="test", backstory="test", llm="gpt-4o-mini"
)
@@ -365,6 +368,9 @@ class TestRuntimeStateIntegration:
def test_runtime_state_roundtrip_with_record(self):
from crewai import Agent, Crew, RuntimeState
if RuntimeState is None:
pytest.skip("RuntimeState unavailable (model_rebuild failed)")
agent = Agent(
role="test", goal="test", backstory="test", llm="gpt-4o-mini"
)
@@ -397,6 +403,9 @@ class TestRuntimeStateIntegration:
"""Backwards compat: a bare entity list should still validate."""
from crewai import Agent, Crew, RuntimeState
if RuntimeState is None:
pytest.skip("RuntimeState unavailable (model_rebuild failed)")
agent = Agent(
role="test", goal="test", backstory="test", llm="gpt-4o-mini"
)