大更新,架构调整,数据分析能力提升,
This commit is contained in:
233
tests/test_phase3.py
Normal file
233
tests/test_phase3.py
Normal file
@@ -0,0 +1,233 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Unit tests for Phase 3: Agent Changes
|
||||
|
||||
Run: python -m pytest tests/test_phase3.py -v
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import pytest
|
||||
from data_analysis_agent import DataAnalysisAgent
|
||||
from prompts import data_analysis_system_prompt, final_report_system_prompt
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Task 8.1: _summarize_result
|
||||
# ===========================================================================
|
||||
|
||||
class TestSummarizeResult:
|
||||
@pytest.fixture
|
||||
def agent(self):
|
||||
"""Create a minimal DataAnalysisAgent for testing."""
|
||||
agent = DataAnalysisAgent.__new__(DataAnalysisAgent)
|
||||
agent._session_ref = None
|
||||
return agent
|
||||
|
||||
def test_success_with_evidence_rows(self, agent):
|
||||
"""8.1: Success with evidence rows produces DataFrame summary."""
|
||||
result = {
|
||||
"success": True,
|
||||
"evidence_rows": [{"a": 1, "b": 2}, {"a": 3, "b": 4}],
|
||||
"auto_exported_files": [{"variable_name": "df", "filename": "df.csv", "rows": 150, "cols": 8, "columns": []}],
|
||||
}
|
||||
summary = agent._summarize_result(result)
|
||||
assert "执行成功" in summary
|
||||
assert "DataFrame" in summary
|
||||
assert "150" in summary
|
||||
assert "8" in summary
|
||||
|
||||
def test_success_with_evidence_no_auto_files(self, agent):
|
||||
"""8.1: Success with evidence but no auto_exported_files uses evidence length."""
|
||||
result = {
|
||||
"success": True,
|
||||
"evidence_rows": [{"x": 1}, {"x": 2}, {"x": 3}],
|
||||
"auto_exported_files": [],
|
||||
}
|
||||
summary = agent._summarize_result(result)
|
||||
assert "执行成功" in summary
|
||||
assert "DataFrame" in summary
|
||||
|
||||
def test_success_with_output(self, agent):
|
||||
"""8.1: Success with output but no evidence shows first line."""
|
||||
result = {
|
||||
"success": True,
|
||||
"evidence_rows": [],
|
||||
"output": "Hello World\nSecond line",
|
||||
}
|
||||
summary = agent._summarize_result(result)
|
||||
assert "执行成功" in summary
|
||||
assert "Hello World" in summary
|
||||
|
||||
def test_success_no_output(self, agent):
|
||||
"""8.1: Success with no output or evidence."""
|
||||
result = {"success": True, "evidence_rows": [], "output": ""}
|
||||
summary = agent._summarize_result(result)
|
||||
assert summary == "执行成功"
|
||||
|
||||
def test_failure_short_error(self, agent):
|
||||
"""8.1: Failure with short error message."""
|
||||
result = {"success": False, "error": "KeyError: 'col_x'"}
|
||||
summary = agent._summarize_result(result)
|
||||
assert "执行失败" in summary
|
||||
assert "KeyError" in summary
|
||||
|
||||
def test_failure_long_error_truncated(self, agent):
|
||||
"""8.1: Failure with long error is truncated to 100 chars."""
|
||||
long_error = "A" * 200
|
||||
result = {"success": False, "error": long_error}
|
||||
summary = agent._summarize_result(result)
|
||||
assert "执行失败" in summary
|
||||
assert "..." in summary
|
||||
# The error portion should be at most 103 chars (100 + "...")
|
||||
error_part = summary.split("执行失败: ")[1]
|
||||
assert len(error_part) <= 104
|
||||
|
||||
def test_failure_no_error_field(self, agent):
|
||||
"""8.1: Failure with missing error field."""
|
||||
result = {"success": False}
|
||||
summary = agent._summarize_result(result)
|
||||
assert "执行失败" in summary
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Task 8.2-8.4: Round_Data construction and session integration
|
||||
# ===========================================================================
|
||||
|
||||
class TestRoundDataConstruction:
|
||||
def test_handle_generate_code_returns_reasoning(self):
|
||||
"""8.2: _handle_generate_code returns reasoning from yaml_data."""
|
||||
agent = DataAnalysisAgent.__new__(DataAnalysisAgent)
|
||||
agent._session_ref = None
|
||||
# We need a minimal executor mock
|
||||
from unittest.mock import MagicMock
|
||||
agent.executor = MagicMock()
|
||||
agent.executor.execute_code.return_value = {
|
||||
"success": True, "output": "ok", "error": "",
|
||||
"variables": {}, "evidence_rows": [],
|
||||
"auto_exported_files": [], "prompt_saved_files": [],
|
||||
}
|
||||
yaml_data = {"code": "x = 1", "reasoning": "Testing reasoning field"}
|
||||
result = agent._handle_generate_code("response text", yaml_data)
|
||||
assert result["reasoning"] == "Testing reasoning field"
|
||||
|
||||
def test_handle_generate_code_empty_reasoning(self):
|
||||
"""8.2: _handle_generate_code returns empty reasoning when not in yaml_data."""
|
||||
agent = DataAnalysisAgent.__new__(DataAnalysisAgent)
|
||||
agent._session_ref = None
|
||||
from unittest.mock import MagicMock
|
||||
agent.executor = MagicMock()
|
||||
agent.executor.execute_code.return_value = {
|
||||
"success": True, "output": "", "error": "",
|
||||
"variables": {}, "evidence_rows": [],
|
||||
"auto_exported_files": [], "prompt_saved_files": [],
|
||||
}
|
||||
yaml_data = {"code": "x = 1"}
|
||||
result = agent._handle_generate_code("response text", yaml_data)
|
||||
assert result["reasoning"] == ""
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Task 8.3: set_session_ref
|
||||
# ===========================================================================
|
||||
|
||||
class TestSetSessionRef:
|
||||
def test_session_ref_default_none(self):
|
||||
"""8.3: _session_ref defaults to None."""
|
||||
agent = DataAnalysisAgent()
|
||||
assert agent._session_ref is None
|
||||
|
||||
def test_set_session_ref(self):
|
||||
"""8.3: set_session_ref stores the session reference."""
|
||||
agent = DataAnalysisAgent()
|
||||
|
||||
class FakeSession:
|
||||
rounds = []
|
||||
data_files = []
|
||||
|
||||
session = FakeSession()
|
||||
agent.set_session_ref(session)
|
||||
assert agent._session_ref is session
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Task 9.1: Prompt - intermediate data saving instructions
|
||||
# ===========================================================================
|
||||
|
||||
class TestPromptDataSaving:
|
||||
def test_data_saving_instructions_in_system_prompt(self):
|
||||
"""9.1: data_analysis_system_prompt contains DATA_FILE_SAVED instructions."""
|
||||
assert "[DATA_FILE_SAVED]" in data_analysis_system_prompt
|
||||
assert "中间数据保存规则" in data_analysis_system_prompt
|
||||
|
||||
def test_data_saving_example_in_prompt(self):
|
||||
"""9.1: Prompt contains example of saving and printing marker."""
|
||||
assert "to_csv" in data_analysis_system_prompt
|
||||
assert "session_output_dir" in data_analysis_system_prompt
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Task 9.2: Prompt - evidence annotation instructions
|
||||
# ===========================================================================
|
||||
|
||||
class TestPromptEvidenceAnnotation:
|
||||
def test_evidence_annotation_in_report_prompt(self):
|
||||
"""9.2: final_report_system_prompt contains evidence annotation instructions."""
|
||||
assert "evidence:round_" in final_report_system_prompt
|
||||
assert "证据标注规则" in final_report_system_prompt
|
||||
|
||||
def test_evidence_annotation_example(self):
|
||||
"""9.2: Prompt contains example of evidence annotation."""
|
||||
assert "<!-- evidence:round_3 -->" in final_report_system_prompt
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Task 9.3: _build_final_report_prompt includes evidence
|
||||
# ===========================================================================
|
||||
|
||||
class TestBuildFinalReportPromptEvidence:
|
||||
def test_evidence_included_when_session_has_rounds(self):
|
||||
"""9.3: _build_final_report_prompt includes evidence data when rounds exist."""
|
||||
agent = DataAnalysisAgent.__new__(DataAnalysisAgent)
|
||||
agent.analysis_results = []
|
||||
agent.current_round = 2
|
||||
agent.session_output_dir = "/tmp/test"
|
||||
agent.data_profile = "test profile"
|
||||
|
||||
class FakeSession:
|
||||
rounds = [
|
||||
{
|
||||
"round": 1,
|
||||
"reasoning": "分析车型分布",
|
||||
"result_summary": "执行成功,输出 DataFrame (10行×3列)",
|
||||
"evidence_rows": [{"车型": "A", "数量": 42}],
|
||||
},
|
||||
{
|
||||
"round": 2,
|
||||
"reasoning": "分析模块分布",
|
||||
"result_summary": "执行成功",
|
||||
"evidence_rows": [],
|
||||
},
|
||||
]
|
||||
|
||||
agent._session_ref = FakeSession()
|
||||
prompt = agent._build_final_report_prompt([])
|
||||
assert "各轮次分析证据数据" in prompt
|
||||
assert "第1轮" in prompt
|
||||
assert "第2轮" in prompt
|
||||
assert "车型" in prompt
|
||||
|
||||
def test_no_evidence_when_no_session_ref(self):
|
||||
"""9.3: _build_final_report_prompt works without session ref."""
|
||||
agent = DataAnalysisAgent.__new__(DataAnalysisAgent)
|
||||
agent.analysis_results = []
|
||||
agent.current_round = 1
|
||||
agent.session_output_dir = "/tmp/test"
|
||||
agent.data_profile = "test profile"
|
||||
agent._session_ref = None
|
||||
prompt = agent._build_final_report_prompt([])
|
||||
assert "各轮次分析证据数据" not in prompt
|
||||
Reference in New Issue
Block a user