自愈测试流水线
使用 Synapse 记忆构建能从失败中学习并自动适应的测试流水线。
自愈测试流水线
传统测试套件在 UI 变化时会失败。自愈测试使用 Synapse 记忆从过往失败中学习并适应 — 减少不稳定测试与维护成本。
概念
┌─────────┐ 失败 ┌──────────┐ 存储 ┌──────────┐
│ 测试 │ ───────▶ │ Synapse │ ───────▶ │ 记忆 │
│ 运行 │ │ 记忆 │ │ (失败) │
└─────────┘ └──────────┘ └──────────┘
▲ │
│ 回放 │
│ 下次运行前 │
└─────────────────────┘- 测试运行
- 若失败,存储失败信息(出了什么错、为什么、如何修)
- 下次运行:执行前回放相关失败
- 自动应用已知修复
实现
第 1 步:测试包装器
为每个测试包装记忆回放/存储:
import requests
from datetime import datetime
URL = "https://synapse.schaefer.zone"
MIND_KEY = "mk_..."
def self_healing_test(test_name, test_fn):
"""装饰器:用自愈记忆包装测试。"""
def wrapper():
# 1. 回放该测试的过往失败
past_failures = requests.get(
f"{URL}/memory/search?q={test_name}+failure",
headers={"Authorization": f"Bearer {MIND_KEY}"}
).json()
# 2. 在失败上下文中运行测试
try:
test_fn(known_failures=past_failures)
except Exception as e:
# 3. 存储失败
store_failure(test_name, e, traceback.format_exc())
raise
return wrapper
def store_failure(test_name, error, traceback_str):
requests.post(f"{URL}/memory",
headers={"Authorization": f"Bearer {MIND_KEY}",
"Content-Type": "application/json"},
json={
"category": "mistake",
"key": f"test_failure_{test_name}_{datetime.now().isoformat()}",
"content": f"Test: {test_name}\nError: {error}\nTrace:\n{traceback_str}",
"tags": ["test", "failure", test_name],
"priority": "high"
})第 2 步:自适应测试逻辑
在测试内部检查已知失败并应用修复:
@self_healing_test
def test_login_page(browser, known_failures=None):
browser.goto("https://app.com/login")
# 检查是否之前见过这种页面变化
if known_failures and known_failures.get("results"):
for failure in known_failures["results"]:
if "button moved" in failure["content"].lower():
# 改用 accessibility 标签而非坐标
browser.click(by_label="Login button")
return
# 默认:使用坐标
browser.click(x=150, y=400)第 3 步:恢复策略
把恢复策略作为记忆存储:
def store_recovery(failure_type, strategy):
requests.post(f"{URL}/memory",
headers={"Authorization": f"Bearer {MIND_KEY}",
"Content-Type": "application/json"},
json={
"category": "skill",
"key": f"recovery_{failure_type}",
"content": strategy,
"tags": ["test", "recovery", failure_type],
"priority": "high"
})
# 为常见失败存储恢复策略
store_recovery("element_not_found",
"When element not found by ID, try by CSS class, then by XPath, "
"then by accessibility label. Take screenshot for debugging.")
store_recovery("timeout",
"Increase timeout to 30s. If still fails, check if page is loading "
"dynamically — wait for specific element instead of fixed time.")
store_recovery("stale_element",
"Re-find element before each interaction. Don't cache element references "
"across page transitions.")第 4 步:CI 集成
# .gitlab-ci.yml
test:self-healing:
script:
- export SYNAPSE_MIND_KEY=$SYNAPSE_TEST_MIND_KEY
- pytest tests/ --self-healing
after_script:
# 汇总新失败
- python scripts/synapse_failure_summary.py第 5 步:失败分析仪表板
# 获取最近一周的所有测试失败
r = requests.get(
f"{URL}/memory/search?q=test+failure",
headers={"Authorization": f"Bearer {MIND_KEY}"}
)
# 按测试名分组
failures = {}
for mem in r.json().get("results", []):
test_name = extract_test_name(mem["content"])
failures.setdefault(test_name, []).append(mem)
# 报告
for test, fails in sorted(failures.items(), key=lambda x: -len(x[1])):
print(f"{test}: {len(fails)} failures")最佳实践
常见失败模式存储
| 失败类型 | 存储内容 |
|---|---|
| 元素未找到 | 尝试的选择器、页面状态、截图 |
| 超时 | 等待时间、等待的对象 |
| 断言失败 | 期望值与实际值 |
| 网络错误 | URL、状态码、响应体 |
| 权限被拒 | 所需权限、当前用户角色 |