用例分级体系:冒烟、回归、全量背后的成本逻辑

新板子焊好,第一件事不是跑功能,而是上电,看冒不冒烟——不冒烟,才值得往下测。软件测试借用了这个思路:每次提交,先用最小的一组用例回答一个问题——”这个版本是不是明显坏的?“如果是,后面所有测试都别浪费资源了。

但冒烟只回答了”五分钟之内查什么”。一个真实项目的用例库有几百上千条:夜间跑什么?周末跑什么?发版前跑什么?这篇文章把三件事串起来讲:冒烟这一层怎么设计,分级背后的成本账怎么算,以及落地手段——一套用例库怎么跑出 N 种跑法。

一、冒烟测试:上电,看冒不冒烟

冒烟要回答的唯一问题是”这个版本是不是明显坏的”。围绕这个问题,它有五条设计原则:

原则 要求 反面教材
快 总时长 5~10 分钟硬上限(MR 反馈超过 10 分钟,开发者就会绕过门禁) 冒烟跑着跑着膨胀到 40 分钟
广而不深 每个关键模块碰一下,不追求边角 在冒烟里测某模块的 50 个边界条件
只抓”灾难级”故障 目标故障类型:起不来、连不上、核心路径断、数据全错 想抓逻辑细节错误(那是全量回归的活)
零 flaky 容忍 冒烟里出现一次不稳定用例,立刻隔离或修——冒烟红必须等于”真坏了” 团队养成”冒烟红了重跑一遍就好”的习惯,门禁就此失效
每次提交必跑 是门禁(gate),不过就合不进去 变成”参考性检查”,红了也能合并

用例怎么选?从全量库里筛那 20 条,先过三问(都答”是”才进冒烟):

  1. 这条挂了 = 版本基本不可用吗?(P0 级核心旅程:能启动、能通信、核心功能走通)
  2. 它历史上抓到过真 bug 吗?(从没失败过的用例是”装饰”,优先级往后排)
  3. 它跑得快且稳吗?(单条 ≤30 秒、连续百次零波动)

再按覆盖面补齐:每个关键模块/接口至少一条——覆盖的是”面”不是”点”。典型配比:启动/构建类 20%、核心功能 happy path 50%、关键接口 20%、一条端到端 10%。

二、一个 5 分钟的冒烟长什么样

嵌入式/汽车场景的时间预算示例(5 分钟盘):

0:00-0:30  拉代码 + 增量编译(ccache/分布式编译命中)
0:30-1:00  静态检查快档(MISRA 高危规则子集,不是全量)
1:00-2:00  单元测试冒烟档(GTest 按标签筛 ~200 条,并行跑)
2:00-2:30  vECU 启动测试:镜像加载、调度器起 tick、自检通过
2:30-4:00  总线/诊断 sanity:vcan 上收发一帧、UDS 0x10 切会话 +
           0x22 读版本 + 0x27 解锁一轮(三个服务能应答就证明诊断栈活着)
4:00-5:00  一条端到端 SIL 场景:回放 10 秒数据 → verdict 判定 → 报告生成

每一条失败都直接说明”哪个大器官坏了”——这就是”广而不深”的意义。

让它”快”的工程手段:

两条决定冒烟生死的纪律:

  1. 运行时膨胀监控:冒烟总时长进看板,每周超预算就砍——冒烟的最大死因是”大家都想往里塞用例”,要有明确的进出评审:进一条,必须说清它抓哪种灾难级故障;
  2. 失败归因洁癖:冒烟失败必须 100% 可归因到产品问题。环境抖动导致的失败要修环境,不许”重跑通过”糊弄过去——否则三个月后没人再信冒烟。

落地到 CI 很直接:MR 流水线挂冒烟这一个命令,超时 8 分钟兜底;退出码定好门禁语义——0 放行、2 拦产品问题、3 拦工具问题(把 3 单独暴露给值班人,别让它污染”产品挂了”的信号)。

一句话总结:冒烟的功力不在”测什么”,而在”忍住不测什么”——它是一层筛子,筛孔大小决定整条流水线的吞吐;孔太大漏掉灾难,孔太小堵住 MR。

三、分级的本质:一笔经济账

冒烟只解决了”每次提交的 5 分钟”。剩下的用例谁什么时候跑?要回答这个问题,先看清分级的本质——它不是”用例有轻重之分”,而是一个经济学结构:

每条用例的成本随执行频率线性放大,而它提供的信息价值随等待时间衰减——分级就是按”单位成本的信息收益”给用例排班。

先看成本。一条用例的真实价格远不止”跑一遍的机时”:

再看收益。一条用例此刻跑一遍的收益 = 发现回归的概率 × bug 的严重度 × 及时性:

四、三级各自买的是什么

级 预算约束 买什么 选例原则
冒烟(门禁/每次提交) 5~10 分钟 即时反馈:5 分钟内告诉提交者”你搞坏了主干” 失败概率密度最高 + 跑得最快,历史 bug 高发区
回归(夜间) 一个夜间窗口 每日基线:系统整体今天还行不行 主干全部 + 历史缺陷用例 + 需求覆盖
全量(周末/发版) 周末 / 发版窗口 覆盖率证据和长尾 一切,包括一年挂不了一次的边角

反直觉的一点:分级的分界线是”反馈时效”,不是”用例重要性”。 冒烟集不是”最重要的用例”,是”性价比最高的早警系统”——一条重要但要跑 40 分钟的用例,放冒烟里是负收益(拖垮反馈环),放夜间正好。

所以冒烟集别拍脑袋定:把用例按”历史失败次数 ÷ 执行时长”排序,前 20% 就是候选——用真实数据画分级边界,比评审会上拍出来的靠谱。

五、三条工程推论

  1. 门禁时长上限是工程师的耐心,不是技术约束。 5~10 分钟是心理阈值——超过就会被绕过(本地不跑、直接推、跳过检查)。门禁一旦被绕过,整套体系崩溃。所以冒烟集超时的修法是减用例,不是延阈值;
  2. 分级是活的,用例要在级之间流动:flake 的降级(它烧信任,留着是负资产)、新抓到的 bug 的用例升级进回归(历史缺陷是最准的”失败概率”预测器)、多年安静的边角降级到全量。KPI 看缺陷逃逸率:逃逸到下一级的 bug 越多,说明上一级筛选失灵;
  3. 合规约束高于经济约束:ASIL 等级高的用例不参与降级——它的收益不体现在”发现 bug 的期望”上,体现在”审核时必须出示执行证据”上。所以全量层不可省略,分级是”各就各位”,不是”砍掉贵的”。

六、汽车行业:同一套账,被机时放大

SIL 层这套账已经成立;到 HIL 层被机时放大 10~100 倍——HIL 的”全量”被压成”周末/发版”事件。所以汽车行业的分级比互联网行业更陡、更刚性:SIL 每晚全量、HIL 每晚精选、全量攒到发版前——同一套成本逻辑,两个环境的执行参数不同而已。

七、落地手段:给每条用例打标签

账算完了,怎么落地?答案是分层标记:给每条用例打多维正交标签,”跑哪些”变成按标签表达式筛选。 SIL 全量、HIL 子集、CI 冒烟、发版回归,都只是同一用例库的不同视图——不是四个用例库。标签不是分类学,是排班表。

SIL/HIL 场景尤其需要它:

八、标签维度:正交,别揉成一个枚举

维度 典型取值 回答的问题
level unit / component / integration / system 在 V 模型哪层
env mil / sil / pil / hil(多值) 在哪些环境可执行
scope smoke / nightly / regression / release 什么时候跑
req REQ-AEBS-003 追溯到哪条需求
asil QM / A / B / C / D 评审和覆盖率要求

筛选是布尔表达式:env:hil AND scope:nightly AND NOT known_issue。env 必须是多值——同一条 AEB 用例往往 SIL、HIL 都要跑。

九、实现手段,从土到洋

(a) 测试框架自带机制

(b) Manifest 清单(工程主流)

用例元数据和代码分离,一张 tests/manifest.yaml:

- id: TC-ADAS-0042
  path: tests/system/adas/test_aebs.lua    # 或 gtest 套件名
  level: system
  env: [sil, hil]
  scope: [nightly, regression]
  req: [REQ-AEBS-003]
  asil: B

runner 读 manifest → 按表达式筛选 → 生成 gtest filter / 用例列表 → 执行 → 把 req/asil 写进 JUnit XML 的 <properties> 回传 ALM(回传报文里每个 <testcase> 都必须带需求 ID)。

好处:改标签不动代码;可加 lint 强制规则(如”asil:B 以上必须有 req 字段,否则 CI 打回”——正是”合规约束高于经济约束”的代码化:合规用例不参与经济性流动)。Lua 技术栈里还有个更轻的选择:文件头注释 -- @env sil,hil 由 runner 解析,和 manifest 二选一。

(c) 测试管理工具集中管

ECU-TEST 的 package attribute、TestRail / Polarion 自定义字段——本质是 manifest 的数据库版,执行器从工具拉筛选结果。小团队 (b) 够用,主机厂 (c)。

起步原则:先 env + scope + req 三个维度够用,维度多了没人维护。

十、标签和 XIL:一个管”该不该跑”,一个管”能不能跑”

XIL 标准管”脚本怎么访问台架”,不管用例管理;分层标记在 XIL 之上的用例描述层。两者配合:标签决定”该不该跑”,XIL 的环境抽象决定”能不能跑”——同一个脚本,SIL 里连桩、HIL 里连机柜,env: [sil, hil] 两边各跑一遍。(供应链之间交换用例描述还有 ASAM ATX 格式,了解即可。)


回看整条链:冒烟是筛子,分级是排班,标签是排班表。 三者不是三个孤立话题,是同一套成本逻辑从理念到落地的三层。


附:名词解释(按出场顺序)

名词 通俗解释
冒烟测试(smoke test) 用最小的一组用例快速判断”这个版本是不是明显坏了”;名字来自硬件上电看冒不冒烟
门禁(质量门禁) CI 流水线上的自动关卡:不达标就不许合入
MR Merge Request,合并请求;门禁通常挂在 MR 流水线上
flake / flaky(不稳定用例) 同一个用例不改代码、时而过时不过的”神经刀”用例
happy path 一切输入正常时的主流程用例,不碰异常分支
MISRA 汽车嵌入式 C/C++ 编码规范,静态检查常按它出规则
vECU 虚拟 ECU:在 PC 上仿真运行的控制器软件栈
UDS 统一诊断服务(ISO 14229):0x10 切会话、0x22 读数据、0x27 安全解锁都是它的服务 ID
SIL / HIL 软件在环 / 硬件在环;同族还有 MIL(模型在环)、PIL(处理器在环)
缺陷逃逸率 上一级没拦住、漏到下一级才发现的 bug 占比;衡量分级筛选是否失灵
ASIL 汽车安全完整性等级(QM/A/B/C/D,D 最严),ISO 26262 的核心概念
ISO 26262 汽车功能安全标准,要求用例可追溯到需求
GTEST_SKIP() GoogleTest 的运行时跳过宏:条件不具备时记 skip 而非 fail
manifest(用例清单) 与代码分离的用例元数据文件,标签都写在里面
JUnit XML 测试结果的通用上报格式,CI 和测试管理工具都认
ALM 应用生命周期管理工具链,需求—用例—结果的追溯归它管
ASAM ATX 供应链之间交换测试用例描述的标准格式

下一步:

查看全部文章