跨语言的测试要求和口径:测试怎么分层、真实依赖集成、契约测试、不稳定测试怎么治、覆盖率怎么看、验收要留什么证据,以及视觉回归、性能和故障注入的原则。
不规定统一的单元、集成、E2E 数量比例;按风险和系统边界决定每类项目需要哪些测试
怎么检查:评审仓库的测试策略说明,看是否按项目类型写了各类测试的用途,而不是只写比例
为什么、来源
为什么:固定比例套不到 CLI、SDK、桌面客户端这类项目上,还会诱导为凑比例删掉必要的集成测试。
常见组合(示意):
- 后端服务:单元 + 真实依赖集成必有;跨服务时加契约;关键主路径 E2E。
- Web 前端:单元 + 接真实边界的组件集成 + 关键用户旅程 E2E;关键状态可加视觉回归。
- 库或 SDK:单元 + 目标平台集成 + 兼容矩阵;公开接口有契约或 ABI 检查。
- CLI:单元 + 真实子进程与文件系统测试,检查退出码、标准输出和错误输出、带空格的路径和权限。
- 移动端和桌面端见 28–31;调用大模型的应用见 TST-033 和 24。
仓库写明测试策略:项目类型、改动风险分级规则、每级必跑的检查、证据保留多久
怎么检查:CI 检查策略文件存在且字段齐全(可用 JSON Schema 校验)
为什么、来源
为什么:写下来才能跨项目复用和审计,不靠口头约定。
改动按 R0–R3 分级决定必跑检查和审批;改动者只能提高级别,不能自己降级,拿不准按高一级
怎么检查:按改动路径(迁移、权限、策略、锁文件)和接口破坏性差异自动给出最低级别;评审确认或上调
为什么、来源
为什么:所有改动一个流程,要么拖慢小改动,要么放过高风险改动;让改动者自己降级等于没有分级。
| 级别 |
典型改动 |
必跑检查(示意) |
审批 |
| R0 极低 |
注释、排版、不涉及验收规则的文档 |
格式、链接、配置解析 |
常规评审 |
| R1 低 |
局部纯函数、低影响文案 |
lint、构建、相关单元测试 |
常规评审 |
| R2 中 |
新接口、数据库查询、常规页面流程 |
R1 + 真实依赖集成 + 契约(适用时)+ 关键 E2E + 迁移检查 |
非作者评审 |
| R3 高 |
权限、资金、隐私、数据迁移、不可逆操作、并发一致性、接口破坏性变化、跨租户边界、发布通道 |
R2 + 失败恢复与回滚演练 + 负例 + 定向变异测试或模糊测试(适用时)+ 干净环境冒烟 |
独立评审 + 业务负责人 |
这是本主题唯一的风险分级口径。要求更严的业务可以加级别内的检查,不另起一套编号。分支保护和审批的配置方式见 03。
禁止提交聚焦运行(only / focus)、无期限跳过、空断言或恒真断言、吞掉异常、强制成功的测试
怎么检查:用各语言测试框架的 lint 规则检查聚焦与跳过(规则见 10–15);跳过必须带工单号和到期日,CI 检查
为什么、来源
为什么:这些写法让测试永远是绿的,门槛形同虚设。
另见:10-15
修复缺陷时补一个在修复前会失败的回归测试;无法自动化的,附上可复现步骤
怎么检查:评审时看修复 PR 是否带回归测试;可在 CI 里把新测试放到修复前的提交上跑一次,确认会失败
为什么、来源
为什么:修复前不会失败的测试,证明不了它测到了这个缺陷。
改动有语义的生产逻辑时,带上对应的行为测试;纯格式或重命名可以例外
怎么检查:CI 发现生产代码有改动而测试无改动时提示,评审确认例外理由
为什么、来源
为什么:没有测试的行为改动,下次重构时没人知道它被改坏了。
核心路径的测试覆盖正常、边界、无效输入和失败恢复,不只测顺利路径
怎么检查:评审时对照测试清单,看每条核心路径是否有边界和失败用例
为什么、来源
为什么:多数线上故障出在边界和错误处理上,顺利路径的测试抓不到。
削弱断言、删除测试、批量更新快照或截图基线、调低阈值、修改测试配置的改动,必须在 PR 里说明理由并由测试负责人批准
怎么检查:把测试配置、基线目录、质量策略文件写进 CODEOWNERS;CI 识别删除测试和大批量基线更新并打标
为什么、来源
为什么:这些改动能让任何实现「通过」,是最容易被忽视的放水方式。
高风险模块用定向变异测试或人为注入缺陷,检验测试能否发现错误;不要求每个 PR 全量变异或全部杀死
怎么检查:对 R3 模块定期跑变异测试,存活的变异体逐个说明(等价变异可以不杀)
为什么、来源
为什么:行覆盖只说明代码被执行过,不说明断言能发现错误;全量变异成本又太高。
另见:10-15
涉及数据库、消息队列、缓存、文件存储语义的改动,必须有接真实同款组件的集成测试;不用别的引擎冒充(如用 SQLite 代替 PostgreSQL)
怎么检查:CI 里有标记为集成测试的任务,并能看到启动的组件镜像;评审时检查是否用其他引擎代替
为什么、来源
为什么:Mock 和替身引擎验证不了 SQL 方言、事务、索引、并发和协议行为,测过的不是上线的系统。
测试数据相互隔离:每次运行用独立的库、schema 或实例,跑完不影响下一次,能并行;只有能证明所有读写都在同一事务内时才用事务回滚做清理
怎么检查:打乱顺序并行跑两遍测试,结果应一致
为什么、来源
为什么:共享数据会带来顺序依赖和并行冲突;后台任务、DDL、序列等不受测试事务控制,回滚清理会漏。
测试不得连接生产环境的写接口或生产数据库
怎么检查:测试环境的网络策略只放行测试依赖;配置检查禁止测试读取生产连接串
为什么、来源
为什么:测试写进生产会直接造成数据损坏,且难以追溯。
容器化的测试依赖固定镜像摘要,用健康检查等到服务就绪;不把「容器已启动」当成就绪
怎么检查:CI 检查测试用镜像引用带摘要;集成测试框架配置等待策略
为什么、来源
为什么:浮动标签会让结果随上游变化;容器起了服务没起,是集成测试不稳定的常见原因。
时间、随机数、时区、语言环境可注入可固定;随机或属性测试失败时记录种子和缩减后的最小样例
怎么检查:评审时看相关代码是否通过注入的时钟和随机源取值;CI 报告里能看到失败用例的种子
为什么、来源
为什么:不固定就复现不了;时区、夏令时、闰日、月末是常见缺陷来源。
另见:10-15
测试数据默认用合成数据;用真实数据必须先脱敏并经批准;录制回放先替换令牌、时间戳和用户标识;密钥和个人信息不得进入测试制品
怎么检查:对测试数据、录制文件和 CI 制品跑密钥与敏感信息扫描;fixture 标注来源
为什么、来源
为什么:测试制品会被复制、上传、长期保存,泄漏面比生产库还大。
数据库迁移在旧版本的脱敏样本库上验证:升级、核对结构、读写行为;不可逆的迁移不声称可以自动回滚
怎么检查:CI 用上一个发布版本的样本库跑迁移和冒烟测试
为什么、来源
为什么:空库上跑通的迁移,遇到真实数据常常失败。
TST-017硬约束检查:自动对外提供服务的后端供别人引用的库或 SDK 公开接口的改动必须通过 schema 校验和向后兼容检查;破坏性改动要显式标注并走 R3
怎么检查:CI 对接口描述文件跑 lint 和破坏性差异检测(工具见 16)
为什么、来源
为什么:单个服务的测试全绿,证明不了消费方还能用。
有接口描述文件时,用基于 schema 的属性测试检查实现与描述一致;「返回 200」不算契约通过
怎么检查:CI 对运行中的测试实例跑基于 schema 的测试,检查状态码、响应结构和状态流转
为什么、来源
为什么:文件写得再规范,实现和描述也可能不一致;只看状态码会放过结构错误。
有跨团队或独立发布的消费方时,用消费者驱动的契约测试;同仓同团队的内部模块不强上契约中心
怎么检查:评审时看接口的消费方清单:独立发布的消费方是否都有契约,并在提供方 CI 里验证
为什么、来源
为什么:消费者契约能在提供方发布前发现破坏;对同仓内部模块,维护成本通常大于收益。
UI 测试不得用固定时长等待(sleep)来等页面状态
怎么检查:用 E2E 框架的 lint 规则禁止固定等待(如 Playwright 的 waitForTimeout)
为什么、来源
为什么:固定等待在快机器上浪费时间、在慢机器上照样失败,是 UI 测试不稳定的头号原因。
UI 测试用面向用户的定位方式(角色、可见文本、标签)和会自动重试的断言,断言用户看得到的结果;不只断言 CSS 类名或内部状态
怎么检查:lint 提示基于 CSS 或 XPath 的定位;评审时看断言对象
为什么、来源
为什么:绑定实现细节的测试一重构就坏,却抓不到用户真正遇到的问题。
使用视觉回归时,截图基线只在固定的环境(镜像、浏览器、字体)里生成和更新,基线变化在 PR 里评审
怎么检查:基线只由 CI 的指定任务生成;基线目录写进 CODEOWNERS
为什么、来源
为什么:操作系统、浏览器、字体、显卡不同,截图就不同;随手在本机更新基线等于取消了这道检查。
视觉回归只覆盖关键页面和关键状态,不把全站全页截图作为每个 PR 的门槛
怎么检查:评审视觉测试清单,看每张截图对应的页面或状态是否必要
为什么、来源
为什么:截图越多,偶然差异带来的误报越多,最后大家习惯性一键更新。
重试后才通过的测试必须标为不稳定(flaky),保留每次尝试的结果;不得报告为一次通过
怎么检查:测试报告保留每次尝试;CI 汇总时单列「重试后通过」
为什么、来源
为什么:重试是诊断手段;把重试后的绿灯当成通过,会掩盖真实的回归和竞态。
隔离不稳定测试时登记负责人、跟踪工单和到期日;到期未修恢复阻断;R3 路径的测试不长期隔离
怎么检查:隔离清单放在仓库里,CI 检查必填字段和到期日
为什么、来源
为什么:没有期限的隔离会变成永久删除,质量债看不见。
定期统计不稳定测试的比例和排名,按环境、并行度、时区分开看,优先修影响最大的
怎么检查:从 CI 历史报告汇总「重试后通过」的运行占比,每个周期出一份排名
参考值:起步参考值:重试后才通过的运行占总运行数低于 0.5%。无行业出处,按团队自己的基线校正。
为什么、来源
为什么:不统计就只能凭印象,等到大家都不信 CI 时已经晚了。
覆盖率只作信号,不设全局硬门槛,不单独决定能否合并;改动部分的覆盖率可以作参考
怎么检查:CI 报告整体和改动部分的覆盖率;核心模块覆盖下降时要求在 PR 里说明
参考值:起步参考值:改动部分覆盖 70%–80% 作为提醒线,不作放行条件。无行业出处,按模块风险调整。
为什么、来源
为什么:覆盖率只说明哪些代码被执行过;硬门槛会诱导写没有断言的测试来凑数。
区分三个问题:行或分支覆盖(哪些代码跑过)、改动部分覆盖(新改的代码跑过多少)、变异得分(断言能不能发现注入的错误)。三者都不能证明业务正确。生成代码、平台胶水代码可以单独计口径。
发布阻断的检查必须在可信 CI 上对最终提交执行;本地结果、截图和口头报告不算通过
怎么检查:分支保护只认指定 CI 上报的检查结果(见 03)
为什么、来源
为什么:本地环境不可复核,自述的结果可能来自旧提交或被改过的测试。
每项检查的结果用「未运行、通过、失败、已跳过」之一记录;已跳过要写原因,条件型检查要写明为什么不适用
怎么检查:CI 汇总报告时检查每项必跑检查都有状态;已跳过的项缺少原因时报错
为什么、来源
为什么:「没跑」和「跑过了」混在一起,评审者就无法判断结论是否成立。
- 状态名只用词表里的「证据状态」。
- 「不适用」不是状态:适用性判断要由规则给出(如改动没碰接口描述文件,所以跳过契约检查),并记录在报告里。
验收记录至少绑定完整提交 SHA、CI 运行编号和原始测试报告;R3 改动再加锁文件和运行环境摘要、制品摘要
怎么检查:CI 生成证据清单并校验必填字段;原始报告(如 JUnit XML)随运行保存
为什么、来源
为什么:只贴截图或摘要证明不了是哪次提交、哪个环境跑出来的结果。
- 最小集:完整提交 SHA、CI 运行编号、执行者身份、原始报告、各检查的证据状态。
- R3 再加:锁文件摘要、测试套件摘要、运行环境(镜像摘要等)、交付制品摘要;需要时用 CI 的制品证明做签名。
- 证据保留期按组织合规要求定,写进测试策略(TST-002)。
源码、锁文件、测试代码、运行配置或测试策略变化后,相关的验收结果失效要重跑;合并前对最终合并结果再验证
怎么检查:用分支保护的「合并前必须与目标分支同步」或合并队列(配置见 03);用合并队列时 CI 要响应合并组事件
为什么、来源
为什么:旧提交的绿灯不能替新提交作证;只验 PR 分支不验合并结果,会漏掉并发合并带来的冲突。
失败时保留能复现的材料:UI 留 trace 和截图,CLI 留命令、退出码和输出,数据库留语句和状态
怎么检查:CI 在失败时自动上传对应制品,并检查制品是否存在
为什么、来源
为什么:失败了没有材料,只能重跑碰运气;每次都全量录制又太贵,所以只在失败时保留。
调用大模型的功能要有一层可阻断发布的确定性检查:输出结构、工具参数、权限、执行后的真实状态;语义质量的评测方法见 24
怎么检查:测试直接检查系统状态、文件和数据库,而不是模型或工具返回的「已完成」
为什么、来源
为什么:模型输出不确定,语义评分也会漂移;确定性的那一层才能稳定拦住越权和错误副作用。
TST-034软指导检查:自动对外提供服务的后端命令行工具桌面应用移动端(跨平台)私有化或断网部署 要交付安装的产品,每个发布构建在干净环境里安装、启动、迁移或升级并做冒烟测试,测的是最终制品而不是源码
怎么检查:CI 在全新容器或虚拟机里安装发布制品,检查退出码和健康检查
为什么、来源
为什么:源码测试通过不等于制品可用,打包、依赖和构建脚本都可能引入差异。
要求断网部署的产品,在无外网的环境里跑一遍安装和测试;浏览器、镜像、字体、模型等依赖全部预置
怎么检查:CI 里有禁用外网的任务跑完整安装和冒烟测试
为什么、来源
为什么:「工具是开源的」「有容器」不等于能离线,浏览器、字体、模型常在首次运行时下载。
对超时、断线、重复投递、部分写入、依赖不可用等故障做注入测试,验证重试、幂等和恢复;R3 改动必须覆盖
怎么检查:集成测试里用故障代理或测试替身制造故障;评审 R3 改动时检查对应用例
为什么、来源
为什么:只测成功路径的系统,在第一次网络抖动时才暴露问题。
性能要求写成可测的场景和指标,在固定环境里测并和基线比较;不在共享 CI 机器上用绝对耗时做门槛
怎么检查:评审性能测试方案,看场景、指标、环境和基线是否写明
为什么、来源
为什么:共享机器的耗时波动很大,绝对值门槛要么误报,要么被调松到没用。
变异测试全量、长时模糊测试、全量视觉回归、压测放到定时任务或 R3 改动上,不作为每个 PR 的同步门槛
怎么检查:CI 分快检和重检两类任务,统计每类耗时
参考值:起步参考值:PR 快检 10–15 分钟内,定时重检 30–90 分钟。无行业出处,按项目规模调整。
为什么、来源
为什么:PR 反馈太慢,大家就会绕过检查;重检查放到定时任务上同样能发现问题。
用现成的测试工具,不自研浏览器驱动、截图比对、HTTP 模拟、容器管理、变异引擎或压测器
怎么检查:评审新增的测试基础设施代码,看是否已有成熟工具能做
为什么、来源
为什么:这些工具都有成熟的开源实现,自研的维护成本远超收益。
没有符合条件的规则。
测试分层方法
按风险和系统边界组合测试类型(TST-001)
不推荐:固定比例(如 70/20/10)
各语言单元测试、属性测试、变异测试、进程内模拟
各语言库见 10–15
真实依赖集成
Testcontainers(在测试里按需起数据库、队列等容器) · MIT(Java 版已核实;其他语言版本以各自仓库为准)
备选:CI 自带的服务容器或 Compose 隔离环境(不方便在测试进程里管理容器时)
不推荐:用另一种数据库引擎冒充;所有测试共用一个开发库
Web 端到端与 UI 测试
Playwright
备选:Cypress(团队已在用且只测 JS 前端时)
不推荐:自制浏览器驱动、靠固定等待的脚本
Web 视觉回归
Playwright 自带的截图比对,在固定镜像里生成基线
备选:Chromatic(用 Storybook 且接受云服务时)
不推荐:全站全页截图作为 PR 门槛
基于 schema 的接口测试
Schemathesis · MIT
跨团队消费者契约
Pact + 自建 Pact Broker · Pact Broker 为 MIT;自建需自行负责安全和升级
备选:PactFlow(商业托管)(不想自己运维 Broker,且数据可以出内网时)
不推荐:同仓同团队的内部模块也强上 Broker
独立运行的 HTTP 模拟服务
WireMock(独立进程,跨语言;用稳定的 3.x 线) · Apache-2.0
备选:各语言的进程内模拟库(只在单一语言的单元或组件测试里用时(见 10–15))
不推荐:在线 SaaS 模拟服务;手写回放代理或私有 stub 语法
负载测试
k6 · k6 为 AGPL-3.0;作为独立运行的测试工具使用、不随产品分发时,义务和集成进产品不同,口径见 27
备选:Locust(团队以 Python 为主、想用 Python 写场景时)
不推荐:自研压测器
不稳定测试诊断
测试运行器自带的重试与 flaky 标记 + JUnit XML 报告 + CI 历史统计
不推荐:重试多次后只报最终结果
验收证据
CI 原始报告 + 完整提交 SHA + 运行编号
备选:CI 制品证明(如 GitHub 制品证明、Sigstore 兼容方案)(R3 改动或需要向外部证明制品来源时)
不推荐:开发者或 Agent 自己上传截图、自己签「通过」
✕ 错误做法:expect(true).toBe(true) 这类断言凑覆盖率
✓ 应该:断言业务结果和失败路径,必要时用变异测试检验
✕ 错误做法:改代码的同时调低覆盖率门槛、一键更新全部快照
✓ 应该:门槛和基线的改动单独评审
✕ 错误做法:复杂应用全部 mock,从不接真的数据库和队列
✓ 应该:关键语义用真实依赖集成测试
✕ 错误做法:用 SQLite 测、上线用 PostgreSQL,还声称兼容
✓ 应该:测试用和生产同款的引擎
✕ 错误做法:UI 测试里 sleep 5 秒、按 CSS 类名找元素
✓ 应该:语义定位和自动等待的断言
✕ 错误做法:retry=3 后的绿灯当作通过
✓ 应该:记录每次尝试,重试后通过标为不稳定
✕ 错误做法:把截图文件名里写上提交 SHA 当作证据
✓ 应该:用 CI 运行编号、原始报告和制品摘要
✕ 错误做法:升级了依赖还拿旧提交的绿灯合并
✓ 应该:锁文件变化后相关验收失效重跑
✕ 错误做法:「有容器所以一定能离线」
✓ 应该:在断网环境实际跑一遍
✕ 错误做法:把所有测试框架整合成一个自研的「统一测试平台」
✓ 应该:用各语言原生执行器,只统一报告格式和证据清单