# 自愈测试流水线 传统测试套件在 UI 变化时会失败。自愈测试使用 Synapse 记忆从过往失败中学习并适应 — 减少不稳定测试与维护成本。 ## 概念 ``` ┌─────────┐ 失败 ┌──────────┐ 存储 ┌──────────┐ │ 测试 │ ───────▶ │ Synapse │ ───────▶ │ 记忆 │ │ 运行 │ │ 记忆 │ │ (失败) │ └─────────┘ └──────────┘ └──────────┘ ▲ │ │ 回放 │ │ 下次运行前 │ └─────────────────────┘ ``` 1. 测试运行 2. 若失败,存储失败信息(出了什么错、为什么、如何修) 3. 下次运行:执行前回放相关失败 4. 自动应用已知修复 ## 实现 ### 第 1 步:测试包装器 为每个测试包装记忆回放/存储: ```python 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 步:自适应测试逻辑 在测试内部检查已知失败并应用修复: ```python @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 步:恢复策略 把恢复策略作为记忆存储: ```python 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 集成 ```yaml # .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 步:失败分析仪表板 ```python # 获取最近一周的所有测试失败 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") ``` ## 最佳实践 > [!TIP] > - **存储 traceback** — 它们包含失败的确切行 > - **按测试名打标签** — 加速过滤 > - **使用 `mistake` 分类** — 与常规记忆分离 > - **设为 `high` 优先级** — 失败绝不能被遗忘 > - **定期清理** — 删除已解决问题的记忆 > - **不要存储敏感数据** — 凭据、PII ## 常见失败模式存储 | 失败类型 | 存储内容 | |--------------|---------------| | 元素未找到 | 尝试的选择器、页面状态、截图 | | 超时 | 等待时间、等待的对象 | | 断言失败 | 期望值与实际值 | | 网络错误 | URL、状态码、响应体 | | 权限被拒 | 所需权限、当前用户角色 | ## 下一步 - [iOS 自动化测试](/docs/guides/automated-testing-ios) - [记忆最佳实践](/docs/guides/memory-best-practices) - [错误恢复 Cookbook](/docs/llm-cookbook/error-recovery)