AgentEvalTool/tests/unit/test_campaign_view.py
sinohqb 42be31dd1f feat(report): add load_campaign_view as unified campaign read model
活动级读模型单一出口:一次取齐报告 / 探索 / 分析 / 对比四大数据源。
markdown handler 从 30 行拼装逻辑缩到 3 行;分析执行器同步迁移。
comparison.py 内部的 8 次 load_campaign_report 调用暂不动(跨请求冗余,
缓存收益有限,改动风险高)。

- 新增 load_campaign_view(session, campaign) -> dict[str, Any]
- 返回 {report, exploration, analysis, comparison} 四键
- 迁移 markdown handler 和分析执行器两个调用点
- 4 个新测试覆盖 view 的组装逻辑
2026-08-04 11:33:45 +08:00

101 lines
3.4 KiB
Python

"""Tests for load_campaign_view — the unified campaign read model."""
from uuid import uuid4
from agenteval.evaluation.report import load_campaign_view
from agenteval.models import (
Campaign,
CampaignPlanEntry,
CampaignStatus,
Case,
CaseType,
EvalTarget,
Scenario,
)
from agenteval.storage.repository import (
CampaignAnalysisRepository,
CampaignRepository,
ScenarioRepository,
TargetRepository,
)
def _seed_campaign(db_session, *, status=CampaignStatus.COMPLETED):
target = TargetRepository(db_session).create(
EvalTarget(id=f"t-{uuid4().hex[:8]}", name="数字员工")
)
scenario = ScenarioRepository(db_session).create(
Scenario(
id=f"s-{uuid4().hex[:8]}",
name="查账单",
target_id=target.id,
cases=[Case(id="c-1", type=CaseType.SINGLE, messages=["你好"])],
)
)
campaign = CampaignRepository(db_session).create(
Campaign(
name="cycle",
target_id=target.id,
window_seconds=3600,
time_scale=1.0,
plan=[CampaignPlanEntry(scenario_id=scenario.id, offset_seconds=0, count=1)],
status=status,
started_at=None,
)
)
return campaign
def test_view_returns_all_four_keys(db_session):
"""View always returns report/exploration/analysis/comparison keys."""
campaign = _seed_campaign(db_session)
view = load_campaign_view(db_session, campaign)
assert "report" in view
assert "exploration" in view
assert "analysis" in view
assert "comparison" in view
def test_view_with_no_analysis_or_comparison(db_session):
"""No analysis, no comparison, no exploration → those keys are None."""
campaign = _seed_campaign(db_session)
view = load_campaign_view(db_session, campaign)
assert view["report"] is not None
assert view["analysis"] is None
assert view["comparison"] is None
assert view["exploration"] is None
def test_view_with_completed_analysis(db_session):
"""Completed analysis row → analysis key is non-None."""
campaign = _seed_campaign(db_session)
analyses = CampaignAnalysisRepository(db_session)
analyses.upsert(campaign.id, status="completed", result={"summary": "ok"})
view = load_campaign_view(db_session, campaign)
assert view["analysis"] is not None
assert view["analysis"]["summary"] == "ok"
def test_view_with_comparison(db_session):
"""Completed comparison row → comparison key is non-None and contains metric_diff."""
campaign = _seed_campaign(db_session)
# Create a baseline campaign for comparison
baseline = _seed_campaign(db_session)
comparisons = CampaignAnalysisRepository(db_session)
# Mark both as having completed analysis (required for comparison)
comparisons.upsert(baseline.id, status="completed", result={"summary": "baseline"})
comparisons.upsert(campaign.id, status="completed", result={"summary": "current"})
# Create a comparison row
from agenteval.storage.repository import CampaignPeriodComparisonRepository
cmp_repo = CampaignPeriodComparisonRepository(db_session)
cmp_repo.upsert(
campaign.id,
status="completed",
baseline_campaign_id=baseline.id,
result={"evolution": []},
)
view = load_campaign_view(db_session, campaign)
assert view["comparison"] is not None
assert view["comparison"]["status"] == "completed"