mcpField
O
observability-driven-testing

observability-driven-testing

github.com/petrkindlmann测试与质量2221.0k 次安装6 天前更新
代码仓库

关于 observability-driven-testing

一项利用生产环境可观测性发现测试缺口、并将真实错误转化为测试的测试技能,结合基于追踪的断言与遥测数据驱动的优先级排序。

主要功能

  1. 01配置 OpenTelemetry 测试运行器
  2. 02断言追踪结构与延迟
  3. 03将生产错误转为测试
  4. 04按错误率为端点测试排序
  5. 05分析热点路径覆盖率

适用场景

  1. 01验证仅缓存请求未访问数据库
  2. 02根据生产错误创建回归测试
  3. 03结合错误率和流量确定端点测试优先级

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/petrkindlmann/qa-skills --skill observability-driven-testing

安装后在 Claude Code 中输入/observability-driven-testing确认已加载。

附带文件references/log-and-error-pipeline.mdreferences/trace-assertions.md

详细介绍

生产环境是测试设计输入的最丰富来源:每条错误日志、每条慢速跟踪和每次延迟峰值,都能告诉你哪些测试存在缺口。这项技能打通了生产环境可观测性与测试创建之间的反馈循环,并将跟踪结构作为测试断言。原本应当仅使用缓存的路径却悄悄访问了数据库,虽然返回 `200 OK` 并通过了 HTTP 断言,但跟踪断言能捕捉到这一点。输出:经过埋点的测试运行器、基于跟踪的断言,以及从生产错误到测试的流水线。

快速导航

情况前往
让测试执行发出与应用相关联的跟踪OTel 测试运行器设置(references/trace-assertions.md)
断言调用了哪些服务/不存在错误 span/延迟将跟踪作为测试证据
将 Sentry/Datadog 错误转化为测试生产错误到测试的流水线
决定接下来哪些端点需要测试遥测驱动的测试优先级排序
跟踪断言不稳定,或 span 始终未到达故障模式

探索问题

先检查 .agents/qa-project-context.md。如果该文件存在,请将其作为上下文,并跳过其中已有答案的问题。

可观测性技术栈:

  • 使用了什么 APM/跟踪工具?(Datadog、New Relic、Honeycomb、Splunk Observability/SignalFx、ServiceNow Cloud Observability — 原 Lightstep、Dash0、Jaeger、Grafana Tempo、原生支持 OpenTelemetry)——这决定了如何获取跟踪,以及诊断工作流使用哪种查询语法。
  • 应用中是否埋入了 OpenTelemetry,哪些服务已埋点?——未埋点的服务不可见,也无法通过跟踪进行测试。
  • 使用了什么日志基础设施?(ELK、Loki、CloudWatch、Datadog Logs)——这决定了在哪里通过跟踪 ID 关联日志。
  • 使用结构化日志还是自由格式文本?——结构化日志可解析为测试缺口;自由格式文本则需要先进行指纹识别。

跟踪成熟度:

  • 是否能获取跨服务边界的分布式跟踪?——若不能,只能进行单服务 span 断言。
  • 跟踪采样率是多少?(100%、10%、基于头部、基于尾部)——概率采样会随机丢弃测试所断言的跟踪;必须强制采样测试流量(见“故障模式”)。
  • 能否按错误状态、延迟阈值或自定义属性搜索跟踪?
  • 跟踪是否与日志和指标相关联?——这可以启用示例(指标 → 代表性跟踪 ID),让优先级排序更具体。

生产错误跟踪:

  • 使用什么错误跟踪工具?(Sentry、SmartBear Insight Hub — 原 Bugsnag、Rollbar、Datadog Error Tracking、LaunchDarkly Observability — 包含会话回放,原 Highlight.io)
  • 如何对生产错误进行分类处理?(自动、手动、忽略)
  • 是否有将生产错误转化为测试用例的流程?
  • 最近一次本应由测试捕获的生产错误是什么?

测试基础设施:

  • 测试能否发出遥测数据?(跟踪、自定义指标、结构化日志)
  • 测试结果是否与应用遥测数据相关联?
  • 是否有测试到代码的覆盖率映射?——这是计算下文错误率与覆盖率矩阵的必要条件。

核心原则

1. 生产数据决定测试优先级

最有价值的测试能够防止真实的生产错误,而不是理论上的边缘情况或刻意编造的场景。生产错误日志是一份经过优先级排序的待办清单,列出了本应编写的测试,并按照真实用户实际遇到的问题排序。

2. 跟踪是测试证据

“API 返回了 200”只能证明端点有响应。“请求命中了缓存、跳过了数据库,并在 <50ms 内返回”才能证明系统在每一层都按预期运行。跟踪能让测试更深入,而不会增加测试的不稳定性。

3. 可观测性缺口就是测试缺口

没有跟踪、日志或指标的代码路径是不可见的——在生产环境中无法测试,在事件期间也无法验证。可观测性覆盖率和测试覆盖率是同一个问题的两个视角。

4. 闭合反馈循环

完整周期:发现错误 → 分析 → 编写测试 → 部署 → 防止错误再次发生。如果团队发现了生产环境错误,却没有系统地创建测试,同类错误就会再次发生。


将跟踪数据作为测试证据

将 @opentelemetry/semantic-conventions 固定到一个确切版本,并将 sem-conv 升级视为破坏性变更。 跟踪断言通过字符串引用属性名称;这些名称会在不同版本间变化,导致断言在不报错的情况下失效。v1.41.0(2026 年 4 月)引入了 GenAI 破坏性变更和 process.executable 实体拆分,并将 graphql.document 从 Recommended 调整为 Opt-In。固定具体版本,并有意进行升级:

// package.json — 固定确切版本,不使用插入符
"@opentelemetry/semantic-conventions": "1.41.1"
npm install --save-exact @opentelemetry/[email protected]

不要引入新的 OpenTracing 兼容垫片。 OTel 规范于 2026 年 3 月弃用了 OpenTracing 兼容层(最早也要到 2027 年 3 月才会移除);新的插桩应使用原生 OTel API 和 OTLP。

以下三种模式均见 references/trace-assertions.md:

  • 在测试基础设施中集成 OpenTelemetry — 创建实际的测试 span,并通过 service.name、test.suite 和 test.run_id 将其与应用跟踪关联起来。在同一工作进程中初始化并等待 sdk.shutdown() 完成。协调器的全局 teardown 无法刷新工作进程中的 SDK。使用工作进程 fixture 或测试进程 teardown 钩子,然后验证最后一个预期 span 已到达收集器;仅执行 shutdown 不能证明数据已送达。
  • 基于跟踪数据的断言 — 对跟踪结构、span 属性和时序进行断言(调用了哪些服务、没有 ERROR span、根 span 延迟、DB 操作),而非只检查 HTTP 状态。对于单元级 span 检查,使用进程内的 InMemorySpanExporter + SimpleSpanProcessor 并同步读取 getFinishedSpans()——无需网络、无需 waitForTrace,也不会因超时而偶发失败。跨进程跟踪才使用真实收集器 + waitForTrace 流程。
  • 跨服务的分布式跟踪验证 — 使用 assertTraceStructure 辅助函数,验证请求是否按预期顺序流经各个服务,并检查每个 span 的属性和 maxDuration。

对于声明式的基于跟踪数据的断言(通过 YAML/UI 驱动,而非手写 span 查询),开源项目 Tracetest(kubeshop/tracetest)仍可用,但最近一次公开的开源版本是 v1.7.1(2024 年 10 月),近期活动较少——采用前请先评估其维护情况。Tracetest 的商业 Cloud 服务已于 2024 年 10 月结束生命周期;不要设置 Tracetest Cloud,用户会遇到一个已停止的产品。


日志驱动的测试设计

分析生产错误日志,找出测试缺口

生产环境错误是创建测试时优先级最高的输入。每个未处理的错误都意味着缺少一个测试。请参阅 references/log-and-error-pipeline.md,了解 analyze-production-errors.ts 脚本;该脚本会将每个生产错误映射到测试覆盖情况,根据发生频率和最近发生时间分配优先级,并根据错误特征建议测试层级(单元测试/集成测试/e2e 测试)。

对错误分类:已覆盖与未覆盖
1. Export production errors from error tracker (Sentry, Insight Hub, etc.)
   - Filter: last 30 days, count > 5 (ignore one-off errors)
   - Group by: error message fingerprint

2. For each error group:
   a. Does a test exist that would catch this error?
      → Yes: the test is either not running or has a gap (investigate)
      → No: this is a test gap (create a test)

   b. What layer should the test live at?
      → TypeError, null reference → unit test
      → Timeout, connection error → integration test with fault injection
      → UI rendering error → E2E test
      → Data inconsistency → contract test or database test

3. Output: prioritized list of tests to create, ordered by:
   error frequency × user impact × recency
按错误频率和影响确定测试创建优先级

根据频率(高/低)和影响(高/低)组成的 2×2 矩阵确定优先级:P0 = 高频 + 高影响(立即修复),P1 = 低频 + 高影响(下个 sprint),P2 = 高频 + 低影响(本 sprint),P3 = 两者都低(待办事项)。影响指标:高 = 支付/身份验证失败、数据丢失、崩溃;低 = UI 小问题、响应缓慢但仍可正常使用。


遥测驱动的测试优先级排序

按错误加权差距对端点评分

根据实际使用量和实际故障情况按比例投入测试精力。Gap Score 是本技能中通用的标准公式:

Gap Score = (error_rate × requests_per_day) / max(test_count, 1)

该公式按错误加权:它根据端点产生的失败请求绝对数量进行排名,并除以现有测试覆盖率。(如果你想采用按流量加权的视角,找出流量高但运行健康的端点,则将 error_rate 替换为 (1 + error_rate)——这是在回答不同的问题,并非矩阵标签的含义。)

错误率与端点测试覆盖率映射
Endpoint           | Requests/day | Error Rate | Test Count | Gap Score
POST /api/orders   | 50,000       | 0.3%       | 2          | 75   CRITICAL
PUT  /api/profile  | 5,000        | 1.2%       | 1          | 60   CRITICAL
DELETE /api/items  | 2,000        | 0.8%       | 0          | 16   HIGH
POST /api/auth     | 80,000       | 0.1%       | 8          | 10   OK
GET  /api/search   | 200,000      | 0.05%      | 15         | 6.7  OK

Gap Score = (error_rate × requests_per_day) / max(test_count, 1)
Labels: CRITICAL ≥ 50, HIGH 12–49, OK < 12.

Action: create tests for endpoints at HIGH or above, highest score first.

以上每个标签都根据公式和所述阈值推导而来——复制公式即可精确复现该矩阵。你可以选择自己的阈值,但必须说明;切勿手动标注。

示例可补全指标 → 跟踪 → 测试的闭环。 当此矩阵中出现高错误率端点时,OTel 示例可让你从错误率指标直接跳转到具有代表性的失败跟踪 ID,然后沿着该跟踪(见下文)编写测试,而不必手动查找匹配的跟踪。

热路径分析

识别生产环境中遍历次数最多的代码路径,并确保其测试覆盖率与之相称。

1. Extract top 20 endpoints by request volume from APM data
2. For each endpoint, trace the code path through services
3. Map each service-level span to test coverage data
4. Identify hot paths with zero or low test coverage

Output:
  /api/checkout → cart-service → pricing-service → payment-service
  Coverage: cart-service (82%) → pricing-service (45%) → payment-service (91%)
  Gap: pricing-service discount calculation has 45% coverage on a critical path
  Action: Add tests for discount edge cases in pricing-service

将端点级流量数据与持续性能分析结合,找出端点内部的 CPU 和内存分配热点,而不只是边界处的热点。OTel 的性能分析信号于 2026-03-26 进入公开 alpha 阶段(OTLP 路径 /v1development/profiles),GA 计划于 2026 年第三季度推出——请勿将其视为已可用于生产环境。如今可用于生产环境的替代方案:Pyroscope、Parca、Polar Signals、Datadog Profiling。无需插桩的 eBPF 性能分析工具(无需更改 SDK):Polar Signals、Parca、Grafana Beyla。

零插桩可观测性——如果无法添加 OTel SDK,eBPF 工具可通过内核系统调用捕获 HTTP/gRPC 跟踪,无需更改代码:Beyla(Grafana)、Cilium Tetragon、Pixie、Coroot。对于 SDK 部署需要数个季度的遗留服务或多语言服务,这类工具很有用。

OTel Weaver 可根据语义约定 YAML 生成类型安全的插桩代码,使跟踪断言与语义约定升级保持同步。如果你要维护自定义约定,或遇到版本间属性漂移,值得采用。


生产错误到测试的流程

本技能中最重要的工作流:将生产环境中的错误转化为可防止问题再次发生的测试。

1. ERROR DETECTED
   Source: Sentry, Datadog, CloudWatch, or any error tracker
   Capture: error message, stack trace, request context, trace ID, user impact

2. REPRODUCE
   - Pull the trace from the observability platform (exemplar → trace ID if available)
   - Identify the exact request parameters and state that triggered the error
   - Reproduce locally or in staging with equivalent input
   - If not reproducible: add targeted logging and wait for recurrence

3. WRITE TEST
   - Choose the right layer (unit for logic bugs, integration for service interactions)
   - Test must fail before the fix (red-green verification)
   - Document the originating production error in the test name or a comment

4. FIX AND DEPLOY
   - Fix the bug; verify the test passes with the fix
   - Deploy fix + test together

5. VERIFY ELIMINATION
   - Monitor the same error in production after deploy
   - Confirm error count drops to zero
   - If it recurs: the fix was incomplete, repeat from step 2

请参阅 references/log-and-error-pipeline.md,其中展示了一个完整测试,该测试基于 Sentry 问题 PROJ-4521(配送地址为空 → 空引用),在 API 层断言返回 400 或 422(取决于你的契约),并检查端到端结账提示。测试名称和注释会记录错误来源、发生频率及上下文——从生产信号创建测试时应遵循这一惯例。

建立团队反馈闭环
  • 每周错误回顾(30 分钟): 从错误跟踪器中按发生频率提取前 10 个新错误。针对每个错误:指定负责人、创建测试,或标记为已知/可接受。错误跟踪器中堆积数千条无人查看的未解决条目,是一种反面模式。
  • 事件关闭门槛: 每次复盘都添加“什么测试可以避免这次问题?”,并在事件关闭前创建该测试(或明确记录这一缺口)。将其纳入检查清单,以便审核,而不是仅停留在设想层面。

诊断工作流

端到端跟踪失败的请求

当测试失败或生产环境发生错误时,使用跟踪准确了解发生了什么。

1. Get the trace ID (from test output, error tracker, or user report)

2. Open the trace in your APM tool
   - Jaeger: /trace/{traceId}
   - Datadog: /apm/traces?traceId={traceId}
   - Honeycomb: query by trace.trace_id

3. Walk the span tree
   - Root span: what did the user request?
   - Child spans: which services were called?
   - Error spans: where did it fail? (which span FIRST shows an error)
   - Slow spans: where did latency accumulate?

4. Correlate with logs
   - Filter logs by trace ID to see every log entry for this request
   - Look for warnings or errors that precede the failure

5. Identify the root cause
   - Is the error in your code, a dependency, or infrastructure?
   - Transient failure or persistent bug?
将测试失败与生产遥测数据相关联

测试失败时,查询可观测性平台:(1)搜索匹配的生产错误消息(最近 7 天);(2)搜索同一 HTTP 路由且状态为 ERROR 的追踪记录。如果有匹配项 → 说明该 Bug 确实存在且正在影响用户,应优先修复。如果没有匹配项 → 可能是仅影响测试的问题,或是尚未出现在生产环境中的新 Bug。这样就能把“可能是偶发问题”转化为“确认影响生产环境”或“仅影响测试的问题”。


反模式

1. 忽视生产信号

错误跟踪器中有 500 个未解决的错误,无人查看;测试套件通过了,团队便认为质量没问题。**修复方法:**每周进行一次上述 30 分钟的错误审查——查看新增错误中排名前 10 的错误,并为每个错误指定负责人、测试,或标记为已知/可接受。

2. 只测试容易观测的内容

团队断言 HTTP 状态和响应时间,却忽略数据一致性、后台任务完成情况和缓存一致性。**修复方法:**为后台任务、缓存操作和异步工作流添加 span,然后对其进行断言。如果某项操作在生产环境中运行,就应该产生遥测数据。

3. 生产环境与测试之间没有反馈循环

SRE 负责处理错误,QA 负责编写测试,双方却没有系统地共享信息,导致同类 Bug 反复出现。**修复方法:**建立从生产错误到测试的流程,以及事件关闭门禁。

4. 添加过多测试监控,却不处理数据

产生了成千上万条指标和日志,却无人分析——徒增成本,没有收益。**修复方法:**先明确你希望测试遥测数据回答的三个具体问题,再构建对应的仪表板;只有提出新问题时才添加监控。

5. 仅将追踪记录用于调试,而不用它们进行断言

追踪记录被当作故障后的调试工具,而非用于防止故障的断言依据。**修复方法:**在集成测试中添加基于追踪记录的断言——检查调用的服务是否正确、查询是否高效,以及是否命中预期的缓存。这些断言可以捕获 HTTP 层断言无法发现的回归问题。

6. 针对概率采样的追踪记录进行断言

头部采样/概率采样会随机丢弃测试正在断言的追踪记录,导致间歇性失败。**修复方法:**对测试流量强制采样(OTEL_TRACES_SAMPLER=always_on 或使用每个请求的覆盖设置),确保记录每一条要断言的追踪记录。


故障模式

症状可能原因修复或检查
waitForTrace 超时,span 始终未到达采样、导出、收集器保留策略,或实际上没有产生 span产生该 span;保留测试流量;确认导出器/收集器已收到数据,并检查运行 ID
缺少上一个测试结束时产生的 span清理操作未等待完成,或在另一个进程中运行在拥有 SDK 的工作进程中等待 sdk.shutdown() 完成;断言收集器已收到最终数据
应用的 span 不属于测试的追踪记录应用未传播 traceparent 标头确认应用读取/转发了 W3C traceparent;检查是否已配置 OTel 传播器
针对 db.system/graphql.document/GenAI 属性的断言突然失败sem-conv 版本升级重命名或移动了该属性将 @opentelemetry/semantic-conventions 固定为精确版本;对比发行说明;有意更新断言
CI 中没有 span 到达收集器CI 网络无法访问 OTEL_EXPORTER_ENDPOINT指向 CI 内收集器的地址;使用下方的验证步骤执行冒烟测试
尽管确实存在错误,status?.code === 'ERROR' 仍无匹配结果收集器将状态序列化为 2/'STATUS_CODE_ERROR',而非 'ERROR'匹配收集器实际输出的值(参见 references/trace-assertions.md 中的说明)

验证

在信任任何跟踪断言之前,先按从小到大的顺序证明遥测链路正常:

# 1. Start a local collector, point the runner at it, run one instrumented test.
OTEL_EXPORTER_ENDPOINT=http://localhost:4318/v1/traces \
OTEL_TRACES_SAMPLER=always_on \
  npx playwright test --grep @trace

# 2. Confirm a span with service.name=integration-tests arrived at the collector
#    (check the collector's debug/logging exporter output, or query your APM).

然后,在代码中,先断言一个已知跟踪 ID 能够解析,再依赖任何结构性断言:await collector.waitForTrace(traceId, { timeout: 10_000 }) 必须返回跨度 — 如果超时,请先修复采样、刷新或传播问题(参见“故障模式”),再添加更多断言。对于单元级跨度检查,InMemorySpanExporter 路径无需收集器即可同步返回跨度。

完成标准

  • 流量排名前 20 的每个端点(来自热门路径矩阵)都能在采样跟踪中解析出至少一个跨度 — 没有任何高流量端点不可见。
  • 至少一个关键用户旅程有基于跟踪的断言,验证服务调用和跨度属性(而不仅仅是 HTTP 状态),并且在 OTEL_TRACES_SAMPLER=always_on 下通过。
  • 针对生产错误分析中发现的已知故障模式,已编写由日志分析启发的测试用例。
  • 已计算错误率/Gap-Score 矩阵,并据此得出至少一组按优先级排序的未测试代码路径。
  • @opentelemetry/semantic-conventions 在 package.json 中固定为确切版本(不带插入符)。
  • 已记录部署后审查(检查清单项目或事后分析条目),确认在将版本标记为稳定之前检查了可观测性信号。

参考文件(位于 references/ 中)

  • trace-assertions.md — OTel 测试运行器设置(包含正确的全局 teardown 刷新和内存导出器替代方案)、强制采样说明、基于跟踪的断言,以及分布式 assertTraceStructure 助手。
  • log-and-error-pipeline.md — analyze-production-errors.ts 测试缺口脚本,以及一个完整的生产错误转化为测试的示例(400 或 422 断言)。

相关技能

  • testing-in-production — 发布期间的安全渐进式发布技术(标志、金丝雀、护栏指标);而本技能使用这些发布产生的遥测数据作为输入,在发布之后设计测试。
  • synthetic-monitoring — 发布之后运行的定时探测,它们本身也会生成遥测数据;这些遥测数据会用于此处的分析。
  • qa-metrics — 将遥测数据推导出的数值(错误率、延迟、Gap Score)转化为质量仪表板和 KPI;本技能生成原始信号,qa-metrics 对其进行汇总。
  • ai-bug-triage — 当输入是一批需要分类和分流的 CI/生产故障时使用;先用它为此处的错误分类步骤提供输入,然后再回来编写测试。

评论

支持 Markdown