关于 testing-in-production
面向 QA 与工程团队的生产环境测试技能,提供通过受控流量、监控指标和回滚机制验证发布质量的方法。内容涵盖功能标记、渐进式发布、生产冒烟测试及回滚验证。
主要功能
- 01功能标记状态测试
- 02渐进式流量发布
- 03发布后冒烟测试
- 04护栏指标与自动回滚
- 05合成账户与非破坏性检查
适用场景
- 01逐步向用户开放新功能
- 02部署后检查关键生产路径
- 03依据指标暂停发布或回滚
- 04验证回滚已恢复服务
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ petrkindlmann/ qa-skills --skill testing-in-production安装后在 Claude Code 中输入/testing-in-production确认已加载。
附带文件references/patterns.mdreferences/rollout-policy.md
详细介绍
快速导航
| 情况 | 前往 |
|---|---|
| 在功能开关后发布功能 | 功能开关测试 |
| 通过关卡将流量从 1% 逐步提升至 100% | 渐进式发布 + references/rollout-policy.md |
| 需要在每次发布后执行检查 | 生产环境冒烟测试 + references/patterns.md |
| 确定哪些数值作为发布关卡 | 护栏指标 |
| 新代码路径尚无用户可见的变化 | 暗发布 |
| 验证回滚确实有效 | 验证 |
调研问题
先检查 .agents/qa-project-context.md。如果文件存在,请将其作为上下文,并跳过其中已有答案的问题。
功能开关系统:
- 你是否有功能开关平台?(LaunchDarkly、Statsig — 现属 OpenAI、GrowthBook、Unleash、Flagsmith、Harness FME — 前身为 Split、自定义平台、无)
- 如何管理开关?(控制面板、配置文件、环境变量)
- 能否将开关定向到特定用户、百分比或细分群体?
- 当前有多少个启用的开关?是否有清理流程?
发布能力:
- 能否只向部分流量发布?(Canary 基础设施、加权路由、功能开关)
- 部署需要多长时间?回滚需要多长时间?
- 是否采用蓝绿部署或滚动部署?
- 能否按区域、用户群体或百分比路由流量?
监控成熟度:
- 已部署哪些可观测性工具?(APM、日志记录、错误跟踪、指标)
- 是否有展示错误率、延迟和业务指标的仪表板?
- 是否根据适当的阈值配置了告警?
- 能否实时对比 Canary 与基线指标?
生产环境访问与安全:
- 谁可以访问生产环境?是否有审批流程?
- 生产环境中是否有专用测试账户?
- 能否在不影响真实用户数据的情况下于生产环境运行操作?
- 是否有生产事故响应流程?
核心原则
1. 生产环境是最终测试环境
预发布环境只是对生产环境的近似模拟。它无法复现生产环境的数据量、流量模式、第三方集成、基础设施特性或用户行为。在生产环境中测试并非鲁莽,反而更贴近现实。关键不在于是否要在生产环境中测试,而在于如何安全地进行测试。
2. 通过控制影响范围来保障安全
每项生产环境测试都必须回答:“如果出了问题,会影响多少用户?”答案必须尽可能小。功能开关、Canary 部署和流量拆分的作用,就是将影响范围从 100% 缩小到 1% 或更低。
3. 始终准备好经过测试的回滚方案
开始任何生产环境测试之前,必须确定回滚机制、对其进行测试,并确保回滚速度足够快。“关闭功能开关”是不错的回滚方案。“重新部署上一版本”也可以接受。“到时候再想办法”不算方案。你从未执行过的回滚只是一个假设,而不是方案——请参阅验证,了解如何证明它有效。
4. 监控是前提,而非锦上添花
没有监控,就无法在生产环境中测试。如果无法实时测量错误率、延迟和业务指标,就无法检测问题。在添加生产环境测试之前,先补齐监控缺口。
5. 生产测试必须无破坏性
生产测试绝不能损坏真实用户数据、向真实用户发送真实通知、从真实支付方式扣款,或造成需要手动清理的副作用。必须使用合成账户、测试标记和隔离资源。
功能标记测试
功能标记是最安全的生产测试机制。它们将部署与发布解耦,并支持即时回滚。
测试标记开启和关闭时的状态
每项带标记的功能都需要在两种状态下进行测试。标记关闭时的路径就是回滚路径,必须可靠运行——使用 setFeatureFlag(name, true|false, { userId: TEST_USER_ID }) 驱动这两种状态。完整的开启/关闭测试组合见 references/patterns.md。
标记生命周期测试
标记并非只有开启和关闭两种状态。它们会在不同状态间转换,每次转换都必须经过验证。
Flag lifecycle:
Created → Targeting internal users → Canary (1%) → Partial (10-50%) → Full (100%) → Cleanup (removed)
Test at each stage:
- Internal: Feature works for internal accounts, hidden from external
- Canary: Metrics are comparable between flag-on and flag-off cohorts
- Partial: No performance degradation at scale
- Full: All user segments work correctly
- Cleanup: Code with flag removed behaves identically to flag-on
清理过期标记
留在代码中的标记会成为技术债务。运行一个每周 CI 作业,查询标记提供方,找出已 100% 推出的且创建时间超过 14 天的标记。这些标记可作为代码清理的候选项——移除标记分支逻辑,只保留已启用的路径。移除标记却不删掉死代码,只完成了一半清理工作。
标记组合测试
多个标记相互影响时,应测试重要的组合。不要测试所有 2^N 种组合——重点测试影响同一用户流程的标记(例如,new-checkout、express-pay、discount-engine-v2 都会影响结账流程)。选出关键组合:全部采用新方案、一个具有代表性的混合状态,以及全部采用旧方案。组合测试循环见 references/patterns.md。
渐进式推出
厂商原生的金丝雀分析。 在手动编写下面的推出策略 YAML 之前,先确认你的平台是否已具备相应功能:LaunchDarkly Guarded Rollouts(基于指标的自动监控渐进式推出,并可自动回滚;自 2026 年初起采用频率学派序贯检验分析模型)、Statsig Auto-tune、Argo Rollouts AnalysisRun、Flagger、Harness Continuous Verification。如果已有这类功能,优先使用——它与指标和回滚机制的集成成本低于维护自定义分析循环。
AI 功能推出是一种独立模式:将模型变体和提示词作为标记值,并配备成本保护措施和紧急停止开关。LaunchDarkly AI Configs / AgentControl(AI Configs 于 2026 年 5 月宣布更名并纳入 AgentControl 品牌体系)是通过渐进式推出上线大模型功能的文档化方案。完整模式见
release-readiness。
金丝雀阶段:1% 到 100%
结构化推出,并为每个阶段设定明确的晋级标准。
| 阶段 | 流量 | 保持时间 | 关键检查项 |
|---|---|---|---|
| 金丝雀 | 1% | 15-30 分钟 | 错误率、崩溃率、异常 |
| 早期采用者 | 10% | 1-2 小时 | P95 延迟、转化率 |
| 部分推出 | 50% | 2-4 小时 | 所有保护措施、业务指标 |
| 全面推出 | 100% | 监控 24 小时 | 长尾问题、批处理作业兼容性 |
自动晋级和回滚
定义可由机器检查的阶段晋级条件——hold_duration 加指标条件(error_rate_5xx < 0.5%、latency_p95 < 500ms、crash_rate == 0)。触发保护措施违规时自动回滚,无需人工批准:error_rate_5xx > 2x_baseline for 5m、latency_p99 > 3x_baseline for 5m、crash_rate > 0.1% for 2m,并分别通知值班人员。应以错误预算消耗速率作为门槛,而非仅看原始倍数,以便发现虽缓慢但仍会突破 SLO 的问题。完整的晋级 YAML、回滚触发条件和 SLO 门槛配置见 references/rollout-policy.md。
验证回滚是否正确触发
自动回滚触发不代表事故已解决。回滚触发后,在确认系统确实已恢复之前,不要宣布“已恢复”:
- 重新运行健康检查冒烟测试,针对生产环境执行(
GET /api/health返回healthy和之前的version)。 - 确认标志/部署状态已恢复——查询标志平台,确认标志已关闭(或部署正在提供之前的构建版本),不要想当然。
- 确认护栏指标已恢复至基线——错误率、P99 延迟和崩溃率均回到部署前的范围内。
- 确认回滚通知已送达值班人员(Slack/PagerDuty),确保有人负责处理事故。
只有以上四项全部满足,才算验证回滚成功。请参阅验证,了解首次用于生产环境之前证明这条链路有效的预演。
生产冒烟测试
部署后的关键路径测试
每次部署后立即运行,作为流水线阶段(而不仅仅是在部署前的 CI 中运行)。这些测试会验证核心功能在生产配置、数据和基础设施下是否正常:/api/health 检查、使用合成凭据进行的身份验证流程、核心数据加载和搜索。配置 retries: 1 和 timeout,避免部署后运行偶发失败,导致流水线因首次短暂故障而受阻。完整的 production-smoke.spec.ts 请参阅 references/patterns.md。
合成用户账号
生产测试账号必须与真实用户明显区分:使用保留的邮箱模式(smoke-test+{env}@yourcompany.com)、is_synthetic = true 标志,并从分析、计费和邮件营销活动中排除。通过管理 API 创建,并优先使用短时效的 OIDC/工作负载身份令牌,而非长期有效的密码。完整约定请参阅 references/patterns.md。
非破坏性断言
生产冒烟测试必须只读,不写入数据。如果无法避免写入,必须在测试夹具拆卸阶段清理,确保测试无论通过还是失败都会执行清理。
不要在 test() 主体内调用 test.afterEach()——Playwright 会在 describe/文件级别注册钩子,因此在测试中途注册的钩子不会安排拆卸操作,并会抛出 test.afterEach() can only be called in a describe block。数据会泄漏。请使用自动清理夹具,记录创建的资源 ID 并在拆卸时删除(或者在一次性脚本中使用 try/finally)。基于夹具的创建-验证-清理模式请参阅 references/patterns.md。
护栏指标
发布期间要监控的内容
| 类别 | 指标 | 比较方法 | 告警阈值 |
|---|---|---|---|
| 错误 | HTTP 5xx 率 | 与部署前基线比较 | 超过基线 2 倍,持续 5 分钟 |
| 错误 | 未处理异常数 | 与部署前基线比较 | 出现任何新的异常类型 |
| 延迟 | P50 响应时间 | 与部署前基线比较 | 超过基线 1.5 倍 |
| 延迟 | P95 响应时间 | 与部署前基线比较 | 超过基线 2 倍 |
| 延迟 | P99 响应时间 | 与部署前基线比较 | 超过基线 3 倍 |
| 业务 | 转化率 | 与 7 天平均值比较 | 下降超过 5% |
| 业务 | 每次会话收入 | 与 7 天平均值比较 | 下降超过 10% |
| 客户端 | 崩溃率(移动端) | 与上一版本比较 | 增加超过 0.1% |
| 客户端 | JavaScript 错误率 | 与部署前基线比较 | 超过基线 2 倍 |
| 基础设施 | CPU 利用率 | 绝对值 | 持续超过 80% |
| 基础设施 | 内存利用率 | 绝对值 | 持续超过 85% |
基线比较
将金丝雀指标与运行上一版本的对照组进行比较,而不应仅与历史数据比较。
Comparison approaches (best to worst):
1. Canary vs. control: split traffic, compare groups in real time (best)
2. Before/after: compare post-deploy metrics to pre-deploy window (good)
3. Historical: compare to same time last week (acceptable for trends)
4. Absolute thresholds: fixed thresholds regardless of baseline (fragile)
统计显著性
对于业务指标(转化率、收入),较小的样本量会产生较大噪声。得出结论前,请等待结果达到统计显著性。
Minimum sample sizes for rollout decisions:
- Error rate: 1,000 requests (errors are rare events, need volume)
- Latency: 500 requests (more stable, converges faster)
- Conversion rate: 5,000 sessions (business metrics have high variance)
- Crash rate: 10,000 app launches (crashes are rare events)
Rule of thumb: if you don't have enough traffic at 1% to reach
significance in 30 minutes, increase to 5% or extend the hold window.
暗发布
暗发布会将新功能部署到生产环境,但对用户隐藏。真实的生产流量会经过新代码路径,而不会对用户造成可见影响。
流量影子测试
将传入请求复制到新服务。比较响应,但不将新响应返回给用户。
Request flow:
User → Load Balancer → Production Service (returns response to user)
↘ Shadow Service (processes request, logs result, discards)
What to compare:
- Response status codes: shadow should match production
- Response body: diff for semantic equivalence (ignore timestamps, IDs)
- Latency: shadow should not be significantly slower
- Error rate: shadow should not produce more errors
并行执行
对于迁移(新数据库、新算法、新服务),在生产环境中同时运行新旧路径。旧路径将结果返回给用户;新路径异步运行、记录差异,并丢弃其结果。持续跟踪匹配率——切换前目标是达到 99% 以上。
Shadow launch timeline:
Week 1: Deploy shadow, start comparing, expect <50% match
Week 2: Fix mismatches, match rate should climb to 90%+
Week 3: Match rate stable at 99%+, handle remaining edge cases
Week 4: Cut over: shadow becomes primary, old becomes shadow
Week 5: Remove old path after 1 week of stability
反模式
在生产环境测试却不进行监控
在没有仪表板和告警的情况下运行生产测试,就像盲目飞行。只有用户报告问题时,你才会知道测试是否造成了问题。 解决方法: 监控是前提条件。添加任何生产测试之前,请确认你能实时查看错误率、延迟和关键业务指标。首次运行测试前先设置告警。
没有回滚计划
“出了问题我们就部署修复”不算回滚计划。在压力之下,修复会耗时更长、引入新 Bug,并延长故障时间。 解决方法: 每项生产测试或发布都必须有一份记录在案的回滚机制,可在 5 分钟内执行——禁用功能标志、恢复到之前的部署,或重定向流量——并且包含一个验证步骤,以确认系统确实已恢复(参见验证)。
在生产测试中执行破坏性操作
会创建真实订单、发送真实邮件或修改真实用户数据的生产测试,不是测试,而是随时可能发生的事故。 解决方法: 使用标记为测试数据的合成账户。对支付和邮件使用沙盒模式。在 fixture teardown 中清理创建的数据,确保清理总会执行。如果某项测试无法做到非破坏性,就不应在生产环境中运行。
仅在成功时运行清理
将清理步骤放在断言之后,意味着断言失败时永远不会执行清理,正好会泄漏本应删除的测试数据。在 test() 主体中调用 test.afterEach() 也是同样的陷阱——它会抛出错误或被忽略。
解决方法: 将 teardown 放入自动清理 fixture 或 finally 块中,确保无论测试通过还是失败都会运行。参见 references/patterns.md。
用生产环境测试取代预生产测试
生产测试是对预生产测试的补充,而非替代。如果 staging 环境出了问题,而你因为它是唯一可用的环境就在“生产环境中测试”,请先修复 staging。 解决方法: 维护可用的预生产环境。生产测试应验证只有生产环境才能验证的内容:真实流量、真实数据量和真实的第三方集成。
金丝雀发布却不进行对比
将部署范围限制在 1% 的流量,却不将金丝雀指标与对照组进行比较,会完全偏离金丝雀发布的初衷。你只是在放慢部署速度,而不是发现问题。 解决方法: 始终将金丝雀指标与基线进行比较。使用并排仪表板或自动金丝雀分析工具(Kayenta、Argo Rollouts analysis)。
过期的功能标志
功能标志完全发布后却从未移除,会不断累积。一年后,你可能会有 200 个相互作用未知的标志,而且每条代码路径都包含没人理解的分支逻辑。 解决方法: 创建每个标志时都设定过期日期。完全发布并稳定运行 2 周后,移除标志及其无用分支。跟踪标志使用时长,并在标志超过过期日期时发出告警。
验证
在首次用于生产环境之前,证明回滚路径确实会触发——从未触发过的回滚只是一个假设。先做最小检查:
- 在预发布环境触发护栏。 在连接了同一
automatic_rollback策略的预发布发布流程中注入故障(例如,强制error_rate_5xx超过2x_baseline,或让健康检查连续失败 3 次)。确认回滚操作在其for:时间窗口内触发。 - 确认已恢复到先前状态。 重新运行健康检查冒烟测试,并断言
status === 'healthy'且version为先前的版本。查询标志平台或部署系统,确认当前提供服务的是先前的构建版本——不要想当然。 - 确认指标已恢复。 错误率、P99 延迟和崩溃率均回到部署前的范围内。
- 确认通知已发送。 回滚警报已送达值班频道(Slack/PagerDuty)。
- 冒烟测试已接入流水线。 对预发布环境运行部署作业,确认部署后冒烟测试阶段确实执行并阻止晋级——
npx playwright test production-smoke.spec.ts的退出码为 0。
如果无法在预发布环境中演示步骤 1–4,则回滚未经验证,发布流程尚未就绪。
Agent 快捷方式: LaunchDarkly、GrowthBook、Unleash、Flagsmith、Statsig 和 Harness FME 均提供对应的 MCP 服务,AI Agent 可在这些检查期间直接切换标志并读取发布指标,而无需手动操作仪表板。
完成标准
- 已记录功能标志发布计划,明确列出各阶段的百分比步骤(1% → 10% → 50% → 100%)以及每个阶段的具名护栏指标。
- 已配置金丝雀分析及自动化的通过/失败标准,因此晋级和回滚决策不需要手动比较指标。
- 每次部署时,生产冒烟测试都会作为流水线阶段运行(而不只是在部署前的 CI 中运行),且该阶段针对生产环境的退出码为 0。
- 已定义并记录回滚触发条件,并在首次用于生产环境之前,通过验证中的预发布试运行演示其能够正确触发(触发护栏 → 触发回滚 → 确认已恢复到先前状态且指标已恢复)。
- 已记录生产测试数据策略,说明使用的是合成用户还是匿名化真实用户,以及如何将其排除在分析和计费之外。
参考文件(位于 references/ 中)
- rollout-policy.md — 完整的晋级标准 YAML、自动回滚触发条件,以及错误预算 / SLO 门禁配置。
- patterns.md — 标志开启/关闭及组合测试、
production-smoke.spec.ts测试套件、合成账户约定,以及基于夹具的非破坏性创建-验证-清理模式。
相关技能
- release-readiness — 整个版本发布的继续/停止决策;生产测试是其中的部署后验证步骤。需要发布检查清单时查看此项,而不是发布机制。
- synthetic-monitoring — 发布完成后持续运行的定时探测。需要持续验证 SLA 时查看此项,而不是发布过程中的安全措施。
- observability-driven-testing — 使用生产环境追踪和日志作为设计新测试的输入。遥测数据告诉你该测试什么时查看此项,而不是需要安全发布时。
- qa-metrics — 护栏指标和发布标准如何接入仪表板与 KPI。
- ci-cd-integration — 将冒烟测试阶段和发布门禁接入流水线。
- test-environments — 生产测试的补充性预生产环境,绝不能取代生产测试。