fix:批量修复了一些问题
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
"""测试 bzzoiro 事件规范化:基于 fixtures/bzzoiro_event.json 的真实字段映射。
|
||||
|
||||
运行(需先 pip-sync requirements-dev.txt):
|
||||
pytest tests/test_bzzoiro_normalize.py -v
|
||||
|
||||
若真实 bzzoiro 字段名与样例不同,断言会失败 —— 这正是本测试的目的:
|
||||
锁定 normalize_bzzoiro 所依赖的字段名,避免上游静默变更导致数据丢失。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from src.data.config import LEAGUE_NAMES
|
||||
from src.data.normalize import normalize_bzzoiro
|
||||
|
||||
FIXTURE_DIR = Path(__file__).resolve().parent / "fixtures"
|
||||
|
||||
|
||||
def load_event() -> dict:
|
||||
with open(FIXTURE_DIR / "bzzoiro_event.json", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
class TestBzzoiroNormalize:
|
||||
"""验证 normalize_bzzoiro 对 fixture 样例的解析结果。"""
|
||||
|
||||
def test_basic_fields(self):
|
||||
"""基础字段:日期、状态、对阵、进球。"""
|
||||
m = normalize_bzzoiro(load_event(), "E0")
|
||||
assert m is not None
|
||||
assert m.home_team == "Home United FC"
|
||||
assert m.away_team == "Away City FC"
|
||||
assert m.match_status == "finished"
|
||||
assert m.home_goals == 2
|
||||
assert m.away_goals == 1
|
||||
assert m.home_ht_goals == 1
|
||||
assert m.away_ht_goals == 0
|
||||
|
||||
def test_shots_mapping(self):
|
||||
"""射门数映射到 home_shots / away_shots。"""
|
||||
m = normalize_bzzoiro(load_event(), "E0")
|
||||
assert m.home_shots == 14
|
||||
assert m.away_shots == 8
|
||||
|
||||
def test_shots_on_target_mapping(self):
|
||||
"""射正数映射到 home_shots_on_target / away_shots_on_target。"""
|
||||
m = normalize_bzzoiro(load_event(), "E0")
|
||||
assert m.home_shots_on_target == 5
|
||||
assert m.away_shots_on_target == 3
|
||||
|
||||
def test_corners_mapping(self):
|
||||
"""角球映射。"""
|
||||
m = normalize_bzzoiro(load_event(), "E0")
|
||||
assert m.home_corners == 6
|
||||
assert m.away_corners == 4
|
||||
|
||||
def test_possession_mapping(self):
|
||||
"""控球率:API 提供 home 值。"""
|
||||
m = normalize_bzzoiro(load_event(), "E0")
|
||||
assert m.home_possession == 58.5
|
||||
|
||||
def test_xg_mapping(self):
|
||||
"""xG 映射到 home_xg / away_xg。"""
|
||||
m = normalize_bzzoiro(load_event(), "E0")
|
||||
assert m.home_xg == 1.85
|
||||
assert m.away_xg == 0.92
|
||||
|
||||
def test_cards_mapping(self):
|
||||
"""黄牌、红牌映射。"""
|
||||
m = normalize_bzzoiro(load_event(), "E0")
|
||||
assert m.home_yellow_cards == 2
|
||||
assert m.away_yellow_cards == 3
|
||||
assert m.home_red_cards == 0
|
||||
assert m.away_red_cards == 0
|
||||
|
||||
def test_fallback_aliases(self):
|
||||
"""回退别名:shots_home → home_shots, xg_home → home_xg。"""
|
||||
raw = {
|
||||
"event_date": "2026-09-12T19:00:00+00:00",
|
||||
"status": "finished",
|
||||
"home_team": "FC Alpha",
|
||||
"away_team": "FC Beta",
|
||||
"home_goals": 1,
|
||||
"away_goals": 1,
|
||||
"shots_home": 10, "shots_away": 5,
|
||||
"sot_home": 4, "sot_away": 2,
|
||||
"corners_home": 3, "corners_away": 2,
|
||||
"possession": 55.0,
|
||||
"xg_home": 1.2, "xg_away": 0.8,
|
||||
"yellow_cards_home": 1, "yellow_cards_away": 2,
|
||||
"red_cards_home": 0, "red_cards_away": 1,
|
||||
}
|
||||
m = normalize_bzzoiro(raw, "SP1")
|
||||
assert m is not None
|
||||
assert m.home_shots == 10
|
||||
assert m.away_shots == 5
|
||||
assert m.home_shots_on_target == 4
|
||||
assert m.away_shots_on_target == 2
|
||||
assert m.home_corners == 3
|
||||
assert m.away_corners == 2
|
||||
assert m.home_possession == 55.0
|
||||
assert m.home_xg == 1.2
|
||||
assert m.away_xg == 0.8
|
||||
assert m.home_yellow_cards == 1
|
||||
assert m.away_yellow_cards == 2
|
||||
assert m.home_red_cards == 0
|
||||
assert m.away_red_cards == 1
|
||||
|
||||
def test_missing_stats_still_normalizes(self):
|
||||
"""缺少统计字段时仍应解析基础数据,统计字段为 None(不伪造)。"""
|
||||
raw = {
|
||||
"event_date": "2026-09-12T19:00:00+00:00",
|
||||
"status": "finished",
|
||||
"home_team": "FC One",
|
||||
"away_team": "FC Two",
|
||||
"home_goals": 3,
|
||||
"away_goals": 0,
|
||||
}
|
||||
m = normalize_bzzoiro(raw, "D1")
|
||||
assert m is not None
|
||||
assert m.home_goals == 3
|
||||
assert m.away_goals == 0
|
||||
# 无数据字段保持 None,不伪造
|
||||
assert m.home_shots is None
|
||||
assert m.home_xg is None
|
||||
assert m.home_possession is None
|
||||
|
||||
def test_unknown_status_drops(self):
|
||||
"""未知状态 → 丢弃(None)。"""
|
||||
raw = {
|
||||
"event_date": "2026-09-12T19:00:00+00:00",
|
||||
"status": "weird_status",
|
||||
"home_team": "A",
|
||||
"away_team": "B",
|
||||
}
|
||||
assert normalize_bzzoiro(raw, "E0") is None
|
||||
|
||||
def test_invalid_date_drops(self):
|
||||
"""无效日期 → 丢弃(None)。"""
|
||||
raw = {
|
||||
"event_date": "not-a-date",
|
||||
"status": "finished",
|
||||
"home_team": "A",
|
||||
"away_team": "B",
|
||||
"home_goals": 1,
|
||||
"away_goals": 0,
|
||||
}
|
||||
assert normalize_bzzoiro(raw, "E0") is None
|
||||
|
||||
def test_same_team_drops(self):
|
||||
"""主客队同名(规范化后) → 丢弃(None)。"""
|
||||
raw = {
|
||||
"event_date": "2026-09-12T19:00:00+00:00",
|
||||
"status": "finished",
|
||||
"home_team": "Same FC",
|
||||
"away_team": "Same FC",
|
||||
"home_goals": 1,
|
||||
"away_goals": 0,
|
||||
}
|
||||
assert normalize_bzzoiro(raw, "E0") is None
|
||||
|
||||
|
||||
# ── 真实响应校验(占位,待替换后取消 skip) ─────────────────────────
|
||||
|
||||
@pytest.mark.skip(reason="待提供真实 bzzoiro event 响应后替换 fixture 并取消 skip")
|
||||
def test_real_response_matches_fixture_structure():
|
||||
"""真实响应应能被 fixture 结构覆盖(字段名一致)。"""
|
||||
# 真实响应粘贴于此,验证 normalize_bzzoiro 解析成功
|
||||
real_response = {}
|
||||
if not real_response:
|
||||
pytest.skip("未提供真实响应")
|
||||
m = normalize_bzzoiro(real_response, "E0")
|
||||
assert m is not None
|
||||
Reference in New Issue
Block a user