【OpsPilot-07】基础模块的接口契约测试与前后端联调验证 项目进入收尾阶段核心模块陆续完工。我的角色从模块开发转向测试验证——但我的测试重点不是完整的故障剧本那需要Agent编排层和真实LLM配合而是验证我负责的基础模块告警接收、知识库检索、根因分析接口的接口契约稳定性和前后端数据一致性。一、告警解析模块的接口契约测试alert_receiver.py 定义了 ParsedAlert 数据类字段包括class ParsedAlert(BaseModel): alert_id: str starts_at: datetime instance: str alertname: str severity: str summary: str labels: Dict[str, str]测试重点标签归一化逻辑LABEL_ALIASES能否正确处理不同来源的告警格式。测试用例输入标签归一化结果状态{job: order-service, app: demo}alertnameorder-service✅ 通过{service: payment, application: pay}alertnamepayment✅ 通过{alertname: HighCPU, instance: 10.0.1.5}直接使用无需归一化✅ 通过空标签或缺失关键字段返回解析错误不崩溃✅ 通过测试方法构造4组测试JSON调用 ParsedAlert.from_raw() 验证输出。# test_alert_receiver.py我写的测试脚本 import json from alert_receiver import ParsedAlert def test_label_normalization(): with open(test_cases/label_variants.json) as f: cases json.load(f) for case in cases: result ParsedAlert.from_raw(case[input]) assert result.alertname case[expected_alertname] print(f✅ {case[name]})三、知识库检索模块的兼容性测试我的 knowledge_base.py 实现了关键词三层匹配alertnames/症状/服务类型。但项目后期我们将知识库升级为向量BM25reranker的混合检索Qdrant存储。我的测试目标是验证两个版本的知识库接口契约一致即输入告警 → 返回 KnowledgeMatch 列表的结构不变。接口契约对比字段我的实现关键词升级后实现向量一致性match_id✅✅一致sourcekeyword / vectorhybrid上游需兼容confidence0.0-1.00.0-1.0一致matched_symptomsList[str]List[str]一致remediationstrstr一致测试发现source 字段取值不同但前端学的 normalizeAlert 兼容层已经处理了这种差异。我的测试验证了即使底层检索方式改变上层接口仍然稳定。四、根因分析接口的格式稳定性测试root_cause_analyzer.py 定义了输出结构class RootCauseAnalysis(BaseModel): candidates: List[Candidate] confidence: float remediation: Remediation class Candidate: description: str confidence: float evidence: List[str]测试目标验证该结构在前后端联调时不被破坏。前端代码直接消费了这个结构interface RootCauseAnalysis { candidates: { description: string; confidence: number; evidence: string[] }[]; confidence: number; remediation: { immediate: string; short_term: string }; }我的测试验证了Python 端输出的字段名、类型、嵌套结构与前端 TypeScript 接口完全匹配。特别是evidence是List[str]不是strremediation.immediate和remediation.short_term都存在confidence是 float不是 string五、前后端联调中的字段映射验证在前后端对接时我的 ParsedAlert 字段映射为前端模型我的字段前端字段映射逻辑alert_idid直接对应starts_attimestamp格式化为 ISO 8601instancehost直接对应alertnamesource直接对应summarymessage直接对应测试方法我构造了包含特殊字符空格、中文、JSON嵌套的测试告警验证映射后前端展示正确。发现问题starts_at 的时区处理。我的代码使用 UTC 时间前端展示时需要转换为本地时间。前端在 normalizeAlert 中增加了时区转换我的测试验证了转换前后时间戳一致不丢失精度。六、测试覆盖度已完成告警解析4组标签归一化测试知识库接口结构一致性验证根因分析格式字段完整性检查前后端字段映射5组边界数据测试七、测试代码片段# test_contract.py —— 接口契约测试脚本 import pytest from alert_receiver import ParsedAlert from knowledge_base import KnowledgeBase from root_cause_analyzer import RootCauseAnalyzer class TestAlertParsing: def test_label_normalization(self): raw {job: order-service, severity: critical} parsed ParsedAlert.from_raw(raw) assert parsed.alertname order-service assert parsed.severity critical def test_missing_required_field(self): raw {job: test} # 缺少 severity with pytest.raises(ValueError): ParsedAlert.from_raw(raw) class TestKnowledgeBaseContract: def test_search_returns_knowledge_match(self): kb KnowledgeBase(knowledge/kb.json) alert ParsedAlert.from_raw({ alertname: DBConnectionPoolHigh, severity: critical }) matches kb.search(alert, top_k2) assert len(matches) 0 assert hasattr(matches[0], confidence) assert 0 matches[0].confidence 1 class TestRootCauseFormat: def test_output_structure(self): analyzer RootCauseAnalyzer() result analyzer.analyze(alert, matches) assert candidates in result assert remediation in result assert immediate in result[remediation]