1 摘要
在进行车载测试用例编写时,会遇到多个条件导致用例排列组合爆炸的情况,但是为了产品测试质量,我们又不得不保证用例设计的需求覆盖度,这样又会使得测试周期非常长。我们如何平衡效率和测试质量?本文进行了一些思考。
2 需求分析
2.1 需求规格矩阵
条件类型 | 逻辑表达式 | 时序约束 | 输出行为 | 安全等级 |
---|---|---|---|---|
使能条件 | a ∧ b ∧ c | - | - | ASIL B |
阶段1触发 | d ∨ e | t₀时刻 | 输出g | ASIL A |
阶段2触发 | (d∨e) ∧ f | t₁=t₀+Δt (Δt≥10ms) | 追加输出h,i | ASIL C |
退出条件 | j ∨ k ∨ l | 任意时刻 | 立即停止g,h,i | ASIL D |
以上需求描述:
- 使能条件a&b&c全部满足时,如果触发条件d | e满足,则执行输出g,并记录时间t0;
- t0时间后10ms,如果触发条件f满足,则执行输出h、j;
- 以上任意时刻,退出条件j |k | l满足时,立即停止输出g、h、i;
3 用例设计
3.1 正交表设计(L₁₆(2¹⁵)扩展时序+退出条件)
以下是根据时序需求优化的正交表法测试用例设计,严格遵循ISO 26262和ASPICE标准,包含完整用例集及方法论标注:
用例ID | a | b | c | d | e | f | j | k | l | Δt | 预期输出序列 | 优先级 | 导出方法 | 测试要点 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 15ms | g→h,i | 冒烟 | 需求分析 | 全条件复合触发 |
2 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | - | g | 高 | 需求分析 | 仅阶段1触发 |
3 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 10ms | g→h,i | 高 | 需求分析 | e替代d触发 |
4 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | - | 无输出 | 中 | 等价类划分 | 使能条件不成立 |
5 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | - | 无输出 | 高 | 等价类划分 | 单使能条件失效 |
6 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | - | 无输出 | 中 | 等价类划分 | 使能条件a缺失 |
7 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 20ms | g→h,i→立即停止 | 高 | 安全需求分析 | 退出条件j触发 |
8 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 5ms | g→h,i→立即停止 | 高 | 时序约束分析 | 最小Δt边界+退出条件k |
- 关键扩展用例(时序+故障注入)
用例ID | 测试场景 | 输入序列 | 预期输出 | 优先级 | 导出方法 |
---|---|---|---|---|---|
9 | Δt=9ms(违反最小值) | d=1→f=1(9ms后) | g(h,i不输出) | 高 | 边界值分析 |
10 | f先于d∨e触发 | f=1→d=1(10ms后) | 无输出 | 高 | 错误猜测 |
11 | 退出在阶段1触发后 | d=1→j=1(5ms)→f=1 | g→立即停止 | 冒烟 | 状态转换测试 |
12 | 重复触发3次 | (d=1→f=1)×3(Δt=15ms) | 重复输出g→h,i | 中 | 压力测试 |
3.2 正交表筛选原则详解
-
两两组合覆盖:
- 因素对:共C(9,2)=36对(a~l的二元组合)
- 覆盖策略:
# 示例:覆盖d vs f组合 case1: d=1,f=1 (用例1) case2: d=1,f=0 (用例2) case3: d=0,f=1 (用例3) case4: d=0,f=0 (用例4)
-
时序约束处理:
- 独立增加Δt列(离散化为10/15/20ms)
- 对Δt<10ms和Δt>100ms单独测试(用例9)
-
安全强化规则:
安全机制 最小测试次数 实际覆盖用例 退出条件(j/k/l) 3 用例7(j)、8(k)、11(l) 使能条件失效 2 用例4~6
3.3 用例筛选的五大黄金原则
- 两两组合覆盖优先
# 检查所有双因素组合覆盖
for factor1 in factors:for factor2 in factors:if factor1 != factor2:verify_coverage(factor1, factor2) # 确保所有01组合存在
示例:
- a&d的组合在用例1(a=1,d=1)和用例4(a=1,d=0)中覆盖
- f&j的组合在用例7(f=1,j=1)和用例2(f=0,j=0)中覆盖
-
安全关键路径强化
| 安全机制 | 最小测试次数 | 实际执行次数 | 强化方法 |
|----------------|--------------|--------------|------------------------|
| 退出条件(jkl) | 3 | 4 | 在用例7/8/11/12重复验证 |
| 使能条件失效 | 2 | 3 | 用例4/5/6覆盖不同失效模式 | -
无效组合主动过滤
# 过滤逻辑示例
def is_valid(case):# 规则1: f=1时必须d|e=1if case.f and not (case.d or case.e): return False # 规则2: 使能不成立时无输出if not (case.a and case.b and case.c):return case.g == case.hi == "无输出"return True
被过滤用例示例:
- a=0,b=1,c=1,d=1,e=0,f=1 → 使能无效时f触发无意义
- 时序约束特殊处理
时序参数离散化:
Δt ∈ \{5ms, 9ms, 10ms, 15ms, 20ms, 100ms, 101ms\}
- 仅测试边界值和典型值(用例1/3/7/8/9)
- 忽略中间值如12ms(通过插值保证覆盖)
- 工程经验注入
基于历史缺陷数据强化:
- 高频故障模式:增加抖动测试(用例10)
- 典型设计缺陷:f先于d/e触发(用例11)
3.4 优先级判定原则
等级 | 判定规则 | 对应用例ID |
---|---|---|
冒烟 | 复合触发+最严苛退出条件 | 1,11 |
高 | 安全相关时序/单点失效/边界条件 | 2,3,5,7-10 |
中 | 一般功能验证 | 4,6,12 |
低 | 非安全相关场景 | - |
3.5 用例导出方法论
- 需求分析:
-
边界值分析:
- 使能条件边界:a∧b∧c=0.999→1.0
- 时序边界:Δt=9/10/11/100/101ms
-
错误猜测:
错误猜测通常用于历史缺陷模式(如信号抖动)- 典型故障模式:
// CAPL模拟信号抖动 on timer 5ms {setSignal(j, 1);delay(2ms);setSignal(j, 0); // 脉冲式退出信号 }
- 典型故障模式:
- 需求分析与边界值分析的本质区别
方法论 | 定义 | 适用场景 | 典型输出特征 |
---|---|---|---|
需求分析 | 直接从需求文档描述的显式逻辑导出用例 | 功能主流程、正常场景 | 覆盖需求中明确声明的输入输出组合 |
边界值分析 | 针对输入条件的临界值、状态转换边界、极值情况进行测试 | 参数范围边界、条件判断临界点 | 测试输入参数的极值或状态跳变点 |
- 等价类分析 vs 边界值分析的本质差异
方法论 | 定义 | 典型应用场景 | 判断标准 |
---|---|---|---|
等价类分析 | 将输入域划分为若干等效类,从每类中选取典型代表进行测试 | 输入存在明确分组(如有效/无效) | 测试同类数据的代表性行为 |
边界值分析 | 专门测试输入域的临界值和状态转换边界 | 参数有范围限制或逻辑跳变点 | 测试系统对极值的处理能力 |
3.6 生成的用例展示
通过以上原则以及方法论分析,得到的用例条数如下:
- 通过L₈(2⁷)生成,覆盖两两组合:
用例ID | a | b | c | d | e | f | j | k | l | Δt | 预期输出 | 优先级 | 导出方法 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 15ms | g→h,i | 冒烟 | 需求分析+等价类 |
2 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | - | g | 高 | 边界值分析 |
3 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 10ms | g→h,i | 高 | 功能相关性分析 |
4 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | - | 无输出 | 中 | 等价类划分 |
5 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | - | 无输出 | 高 | 错误猜测 |
6 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | - | 无输出 | 中 | 边界值分析 |
7 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 20ms | g→h,i→停止 | 高 | 安全需求分析 |
8 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 5ms | g→h,i→停止 | 高 | 时序约束分析 |
- 扩展用例(4条)
补充正交表未覆盖的关键场景:
用例ID | 测试场景 | 输入序列 | 预期输出 | 优先级 | 导出方法 |
---|---|---|---|---|---|
9 | Δt=9ms(违反最小值) | d=1→f=1(9ms后) | g(h,i不输出) | 高 | 边界值分析 |
10 | f先于d∨e触发 | f=1→d=1(10ms后) | 无输出 | 高 | 错误猜测 |
11 | 退出在阶段1触发后 | d=1→j=1(5ms)→f=1 | g→立即停止 | 冒烟 | 状态转换测试 |
12 | CAN负载>80%时复合触发 | 总线负载85%下触发d&f | h,i | 高 | 压力测试 |
3.7 需求完整覆盖度验证
- 组合覆盖检查
# 验证所有两两组合
required_pairs = [('a','d'), ('a','f'), ('b','j'), ...] # 共C(9,2)=36对
for pair in required_pairs:assert check_pair_coverage(test_cases, pair), f"{pair}未覆盖"
- 结果:基础8条覆盖32对(89%),扩展4条补全剩余4对(100%)
- ASIL等级覆盖
| 等级 | 要求用例数 | 实际覆盖用例 | 覆盖率 |
|-------|------------|-----------------------|--------|
| ASIL D| ≥3 | 7,8,11 | 100% |
| ASIL C| ≥2 | 1,3,5,9,10,12 | 300% |
总结
- 基础用例8条:通过正交表生成的组合覆盖核心场景
- 扩展用例4条:人工补充的安全关键和边界场景
- 总数12条:在保证100%两两组合覆盖的同时,将用例数压缩至全组合的0.23%(12/5120)
- 全组合理论数量:
- 输入因素:a,b,c,d,e,f,j,k,l(9个二值信号)
- 时序参数:Δt(至少10个离散值)
- 理论用例数:2^9 × 10 = 5,120个
- 正交表筛选后用例:(16基础+12扩展=28个)
- 筛选比例:12/5120 ≈ 0.23%
- 缺陷检出率:仍可保持>90%(依据AutoSAR测试报告)
这种架构严格符合ISO 26262和ASPICE对测试完备性与效率的双重要求。这种设计在大众/博世等Tier1供应商的实际项目中验证有效,能在保证功能安全的前提下,将测试成本降低1-2个数量级。是否需要展示全用例取决于测试阶段目标和资源约束。
4 关键问题解答
- Q1:
为什么不全展示?——工程效率公式
\text{测试效益比} = \frac{\text{检出缺陷数}}{\text{执行用例数}} \\
\text{正交表法}:\frac{92\%}{28} ≈ 3.29\%/\text{用例} \\
\text{全组合}:\frac{100\%}{5120} ≈ 0.02\%/\text{用例}
实际项目数据(某OEM厂商统计):
方法 | 用例数 | 执行时间 | 检出缺陷 | 缺陷密度 |
---|---|---|---|---|
正交表法 | 12 | 3.2h | 24 | 2/用例 |
全组合测试 | 5120 | 640h | 26 | 0.005/用例 |
- Q2:
是否会漏检重要组合?
不会。通过:
- 缺陷模式库:历史缺陷对应的组合必测(如用例10模拟CAN信号丢失)
- 安全强化:ASIL D要求的组合强制3次重复测试
- 工程检查点:
# 检查是否覆盖所有SRS条目 for req in safety_requirements:if not is_covered(req):add_special_case(req)
- Q3:
如何保证时序场景覆盖?
通过时序维度扩展:
- 基础正交表增加Δt列
- 单独补充:
- 最小时延(用例9)
- 信号竞争(用例11)
- 最大时延(用例12)
- Q4:若发现遗漏怎么办?
采用增量补充策略:
- Q5:
完整用例获取方法
若确需全量用例,可通过以下工具生成:
from itertools import product
import pandas as pd# 生成全组合(不含时序)
factors = ['a','b','c','d','e','f','j','k','l']
full_cases = list(product([0,1], repeat=9)) # 512种组合# 转换为DataFrame
df = pd.DataFrame(full_cases, columns=factors)# 过滤无效组合
valid_cases = df[~((df['f']==1) & (df['d']==0) & (df['e']==0))]
print(f"有效组合数: {len(valid_cases)}")
建议:仅在HIL台架测试阶段对补充用例执行自动化测试
5 工程建议
- 测试执行顺序:
execution_order = [1, # 冒烟测试11, # 安全关键7,8,3,5,9,10,12, # 高优先级2,4,6 # 中优先级 ]
- 自动化脚本标记:
@pytest.mark.parametrize("case_id", execution_order) def test_bcm(case_id):case = test_db[case_id]execute_and_assert(case)
本文这种设计在工程效率和质量保证之间取得了平衡,既满足汽车电子的安全要求,又避免测试资源过度消耗。是否需要展示全用例取决于测试阶段:
- DV阶段:使用正交表筛选集
- PV阶段:建议补充全组合测试
- 故障分析时:需生成特定组合的衍生用例