【OpsPilot-07】基础模块的接口契约测试与前后端联调验证
2026/6/24 5:21:06 网站建设 项目流程

项目进入收尾阶段,核心模块陆续完工。我的角色从模块开发转向测试验证——但我的测试重点不是完整的故障剧本(那需要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"}alertname="order-service"✅ 通过
{"service": "payment", "application": "pay"}alertname="payment"✅ 通过
{"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/症状/服务类型)。但项目后期,我们将知识库升级为向量+BM25+reranker的混合检索(Qdrant存储)。我的测试目标是:验证两个版本的知识库接口契约一致,即输入告警 → 返回 KnowledgeMatch 列表的结构不变。

接口契约对比:

字段我的实现(关键词)升级后实现(向量)一致性
match_id一致
source"keyword" / "vector""hybrid"上游需兼容
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 接口完全匹配。特别是:

  • evidenceList[str],不是str

  • remediation.immediateremediation.short_term都存在

  • confidence是 float,不是 string

五、前后端联调中的字段映射验证

在前后端对接时,我的 ParsedAlert 字段映射为前端模型:

我的字段前端字段映射逻辑
alert_idid直接对应
starts_attimestamp格式化为 ISO 8601
instancehost直接对应
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_k=2) 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"]

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询