fix: use real pydantic instances in executor tests, preserve cache handler across re-validation

- Replace MagicMock fixtures with real Agent/Task instances in
  test_async_agent_executor.py so pydantic validation passes
- Guard CacheHandler creation in Crew.set_private_attrs to avoid
  replacing an existing handler when the model validator re-runs
  during RuntimeState registration
This commit is contained in:
Greyson LaLonde
2026-04-04 03:05:06 +08:00
parent fba56056c0
commit 7f24d74795
2 changed files with 30 additions and 34 deletions

View File

@@ -438,7 +438,8 @@ class Crew(FlowTrackable, BaseModel):
@model_validator(mode="after")
def set_private_attrs(self) -> Crew:
"""set private attributes."""
self._cache_handler = CacheHandler()
if not getattr(self, "_cache_handler", None):
self._cache_handler = CacheHandler()
event_listener = EventListener()
# Determine and set tracing state once for this execution

View File

@@ -6,10 +6,12 @@ from unittest.mock import AsyncMock, MagicMock, Mock, patch
import pytest
from crewai.agent import Agent
from crewai.agents.crew_agent_executor import CrewAgentExecutor
from crewai.agents.parser import AgentAction, AgentFinish
from crewai.agents.tools_handler import ToolsHandler
from crewai.llms.base_llm import BaseLLM
from crewai.task import Task
from crewai.tools.tool_types import ToolResult
@@ -23,31 +25,25 @@ def mock_llm() -> MagicMock:
@pytest.fixture
def mock_agent() -> MagicMock:
"""Create a mock agent for testing."""
agent = MagicMock()
agent.role = "Test Agent"
agent.key = "test_agent_key"
agent.verbose = False
agent.id = "test_agent_id"
return agent
def test_agent(mock_llm: MagicMock) -> Agent:
"""Create a real Agent for testing."""
return Agent(
role="Test Agent",
goal="Test goal",
backstory="Test backstory",
llm=mock_llm,
verbose=False,
)
@pytest.fixture
def mock_task() -> MagicMock:
"""Create a mock task for testing."""
task = MagicMock()
task.description = "Test task description"
return task
@pytest.fixture
def mock_crew() -> MagicMock:
"""Create a mock crew for testing."""
crew = MagicMock()
crew.verbose = False
crew._train = False
return crew
def test_task(test_agent: Agent) -> Task:
"""Create a real Task for testing."""
return Task(
description="Test task description",
expected_output="Test output",
agent=test_agent,
)
@pytest.fixture
@@ -59,17 +55,16 @@ def mock_tools_handler() -> MagicMock:
@pytest.fixture
def executor(
mock_llm: MagicMock,
mock_agent: MagicMock,
mock_task: MagicMock,
mock_crew: MagicMock,
test_agent: Agent,
test_task: Task,
mock_tools_handler: MagicMock,
) -> CrewAgentExecutor:
"""Create a CrewAgentExecutor instance for testing."""
return CrewAgentExecutor(
llm=mock_llm,
task=mock_task,
crew=mock_crew,
agent=mock_agent,
task=test_task,
crew=None,
agent=test_agent,
prompt={"prompt": "Test prompt {input} {tool_names} {tools}"},
max_iter=5,
tools=[],
@@ -231,8 +226,8 @@ class TestAsyncAgentExecutor:
@pytest.mark.asyncio
async def test_concurrent_ainvoke_calls(
self, mock_llm: MagicMock, mock_agent: MagicMock, mock_task: MagicMock,
mock_crew: MagicMock, mock_tools_handler: MagicMock
self, mock_llm: MagicMock, test_agent: Agent, test_task: Task,
mock_tools_handler: MagicMock,
) -> None:
"""Test that multiple ainvoke calls can run concurrently."""
max_concurrent = 0
@@ -244,9 +239,9 @@ class TestAsyncAgentExecutor:
executor = CrewAgentExecutor(
llm=mock_llm,
task=mock_task,
crew=mock_crew,
agent=mock_agent,
task=test_task,
crew=None,
agent=test_agent,
prompt={"prompt": "Test {input} {tool_names} {tools}"},
max_iter=5,
tools=[],