完善评估能力:筛选参数 + degraded 排除 + 前端评估页
后端: - settle_prediction 拒绝 degraded/failed(明确错误信息) - get_eval_summary 支持 provider/model/prompt_version/mode 筛选 - 返回 filtered_settled/evaluated/skipped_degraded 等计数 - matches 游标分页方向修复(scheduled ASC 用 > 条件) - available_at 加 2h 缓冲(近似完赛时间) - bzzziro 统计字段映射注释(待真实响应验证) - injuries 区分 no_local_data 与 success 空名单 前端: - 新增 EvalPage(筛选控件 + 汇总卡片 + 准确率表格) - 挂载 /admin/eval 路由与导航 测试: - test_matches_cursor.py:游标方向 - test_available_at.py:2h 缓冲与回测防泄漏 - test_bzzoirot_stats.py:统计字段映射 - test_injuries_no_local_data.py:no_local_data vs success - test_injuries_inserted_count.py:失败批不计入 - test_eval_excludes_degraded.py:degraded 排除准确率
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
"""回归测试: 伤停切片区分「本地无数据」与「查询成功但空名单」。
|
||||
|
||||
验证:
|
||||
1. API Key 已配置但 injuries 表无任何记录 → has_data=False
|
||||
2. 有历史伤停记录但当前比赛日无缺阵 → has_data=True
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from src.data.injuries import InjuryQueryResult, get_injuries_for_match
|
||||
from src.llm.context_builder import MatchHeader, injuries_slice
|
||||
|
||||
|
||||
def _make_header():
|
||||
return MatchHeader(
|
||||
match_id=999, home_name="A", away_name="B",
|
||||
league_name="X", season=None, match_date="?",
|
||||
match_dt=None, stage=None,
|
||||
home_team_id=1, away_team_id=2, league_id=1,
|
||||
)
|
||||
|
||||
|
||||
class TestNoLocalData:
|
||||
"""区分「本地无数据」与「查询成功但空名单」。"""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_no_local_data_yields_has_data_false(self):
|
||||
"""API Key 已配置但 injuries 表无任何记录 → has_data=False。"""
|
||||
header = _make_header()
|
||||
|
||||
async def mock_query(db, team_id, match_date, as_of=None):
|
||||
return InjuryQueryResult(records=[], query_status="no_local_data")
|
||||
|
||||
with patch("src.data.injuries.get_injuries_for_match", mock_query):
|
||||
result = await injuries_slice(header, before=None)
|
||||
|
||||
assert result.has_data is False, "no_local_data 应 has_data=False"
|
||||
assert "本地尚无伤停数据" in result.text
|
||||
print("PASS: no_local_data → has_data=False")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_success_empty_yields_has_data_true(self):
|
||||
"""API Key 已配置且查询成功 + 空名单 → has_data=True。"""
|
||||
header = _make_header()
|
||||
|
||||
async def mock_query(db, team_id, match_date, as_of=None):
|
||||
return InjuryQueryResult(records=[], query_status="success")
|
||||
|
||||
with patch("src.data.injuries.get_injuries_for_match", mock_query):
|
||||
result = await injuries_slice(header, before=None)
|
||||
|
||||
assert result.has_data is True, "success + 空名单应 has_data=True"
|
||||
assert "当前无伤停记录" in result.text
|
||||
print("PASS: success + empty → has_data=True")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mixed_status_uses_has_data_false(self):
|
||||
"""主队 success + 客队 no_local_data → has_data=False(保守)。"""
|
||||
header = _make_header()
|
||||
|
||||
async def mock_query(db, team_id, match_date, as_of=None):
|
||||
if team_id == 1:
|
||||
return InjuryQueryResult(records=[], query_status="success")
|
||||
return InjuryQueryResult(records=[], query_status="no_local_data")
|
||||
|
||||
with patch("src.data.injuries.get_injuries_for_match", mock_query):
|
||||
result = await injuries_slice(header, before=None)
|
||||
|
||||
# 任一 no_local_data → 保守 has_data=False
|
||||
assert result.has_data is False
|
||||
print("PASS: mixed status保守 has_data=False")
|
||||
Reference in New Issue
Block a user