想象你是一家火锅店的老板,招牌锅底已经稳定卖了三年。有一天你想开发几道“隐藏菜单”——用冷门食材组合出惊喜。你很清楚:单独看每样食材都没问题(牛肉新鲜、榴莲成熟、山泉水干净),但把它们混在一起涮进同一口锅,可能迸发出惊艳风味,也可能让客人当场翻白眼甚至送急诊。 AI 安全测试面对的就是这种局面。模型的每个输入参数单独看都无害,但当某些罕见组合同时出现——比如“超长文本 + 特定编码 + 敏感意图”——可能突然触发漏洞、产生有害输出。这就是「罕见组合测试」:在庞大的输入组合空间里,系统性地找出那些低概率出现、却可能引爆风险的组合,并验证其覆盖是否完整。 在这篇文章里,我们将陪这位火锅店老板一起设计隐藏菜单:先划定试菜范围(测试设计)、选择搭配策略(组合生成)、跟踪尝过的搭配(覆盖度量)、安排试吃节奏(执行监控)、分析踩雷原因(根因分析),最后把成功菜单写进标准手册(回归体系)。全程用一套方法论把稀有输入组合变成可量化的安全防线。

岗位关联

对 AI 从业者而言,这是构建安全评测闭环的必修课:学会用覆盖思维代替盲目堆用例,在资源有限时把测试火力精准对准高风险的稀有组合,为模型上线前的质量保障提供可信依据。

目录
  1. 可视化演示
  2. 测试设计流程
  3. 组合策略生成
  4. 覆盖度量分析
  5. 执行监控机制
  6. 结果根因分析
  7. 回归体系搭建
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示AI评测中罕见组合测试的完整流程:特征建模与用例设计、执行管线自动化、异常判定缺陷闭环与回归测试体系。切换模式查看不同环节。

本节配有交互动效(进入视口后自动加载,约 3KB)。

测试用例设计流程 特征建模提取输入空间的维度组合,覆盖常见与罕见路径 等价类划分+边界值分析生成罕见组合测试用例 cases = comb(features, constraints) 特征建模确保罕见组合被系统性覆盖

测试设计流程

火锅店老板要研发隐藏菜单,第一件事不是下锅,而是先想清楚:店里可供使用的食材有哪些?有什么忌口不能上桌?哪些食材配在一起容易出“事故”?他会在后厨白板上列一张食材清单,标出禁忌组合,再决定先试哪几道菜。测试设计流程做的正是这件事:先划定输入空间,识别参数间的交互关系,再排出试菜优先级。

在 AI 安全测试中,“食材清单”就是模型的输入空间建模。我们要明确模型接受哪些输入参数——比如文本系统的语言类型、文本长度、编码方式、敏感词位置;每类参数的合法取值域是什么——即边界约束识别。接着要判断哪些参数之间存在交互影响:就像火锅里油料和火候会相互影响,参数的值域之间也可能互相放大风险。最后是交互强度选择:是只看单参数(1-wise),还是看两两交互(2-wise),甚至三参数(3-wise)。

交互强度决定了测试的覆盖目标,也直接决定了用例数量。这里有一个绕不开的数学事实:即使每个参数只有少量取值,参数的组合空间也会迅速膨胀。

设计完成后,老板手里有了一张“食材地图”和试菜优先级——先试高风险高价值的搭配,而不是漫无目的地乱涮。好的测试设计,决定了后续所有工作是在打靶还是在撒网。

N=∏i=1k∣Di∣=∣D1∣×∣D2∣×⋯×∣Dk∣\displaystyle N = \prod_{i=1}^{k} |D_i| = |D_1| \times |D_2| \times \cdots \times |D_k|
这个公式算出完整输入空间的总组合数:每个参数取值数的连乘积。4 个参数各 3 个取值时,N=81;再加 4 个参数就突破 6561。全量测试在现实中几乎不可行,所以设计阶段就要选好交互强度。
  1. 参数总数 k参与组合的输入参数个数。比如文本系统里有“语言类型、文本长度、编码方式、敏感词位置”四个参数,k=4。
    k=4\displaystyle k = 4
  2. 单参数取值域 D_i第 i 个参数允许的取值范围集合。取值数记为 \|D_i\|,如语言类型有中/英/日三种,\|D_1\|=3。
    ∣D1∣=3\displaystyle |D_1| = 3
  3. 连乘运算把 k 个参数的取值数逐一相乘。每多一个参数、每多一个取值,组合数都按倍数爆炸式增长。
    N=3×3×3×3=81\displaystyle N = 3 \times 3 \times 3 \times 3 = 81

组合策略生成

拿着食材清单,老板面临三种搭配思路:一是把所有食材组合都做一遍(全组合),厨房直接瘫痪;二是闭着眼随手抓几把(随机采样),全凭运气;三是聪明人做法——保证任意两种食材都至少在一道菜里同框一次(成对覆盖)。这正是组合策略生成的核心分野。

笛卡尔全组合最完备,但如公式所见,组合数爆炸让它很快失去可行性。随机采样搜索节省资源,却无法回答“测够了没有”——它可能重复踩中同一个值对,却对另一些值对视而不见。成对组合覆盖(pairwise)则基于一个重要的工程经验:绝大多数缺陷是由两个参数的交互触发的,只要覆盖所有“两两值对”,就能以远少于全组合的用例捕获绝大部分风险。

要理解 pairwise 要覆盖什么,先看两两交互面有多少个:

除此之外,生成策略还要考虑约束条件过滤:有些组合在业务上根本不可能出现(比如“晴天”和“台风红色预警”同时成立),应该从候选集中剔除,避免生成无效用例浪费算力。老板在试菜前也会划掉“榴莲+止咳糖浆”这种顾客永远不会点的组合——这正是约束过滤的直觉版本。组合策略能高效生成的关键,就是在爆炸的空间里用覆盖思想圈定最小必要集合。

L=(k2)=k(k−1)2\displaystyle L = \binom{k}{2} = \frac{k(k-1)}{2}
这个公式算的是“参数对”的数量:从 k 个参数中任取 2 个有多少种组合。k=4 时有 6 个交互面,每个交互面包含 3×3=9 个值对,共 54 个值对需要覆盖。
  1. 组合数符号\binom{k}{2} 表示从 k 个不同元素中取出 2 个元素的组合数,不关心顺序。
    (42)\displaystyle \binom{4}{2}
  2. 展开计算组合数展开为 \frac{k(k-1)}{2},代入 k=4 后得到 6。
    4×32=6\displaystyle \frac{4 \times 3}{2} = 6
  3. 交互面含义每个交互面对应一对参数之间的所有值对。4 个参数构成 6 个交互面,pairwise 策略要求这 6 个交互面中的每个值对都至少被执行一次。

覆盖度量分析

隐藏菜单试到第几道才算“试够了”?老板不会凭感觉说话,而是在后厨白板上画一张“搭配锁定表”:每道菜试完,就把其中新覆盖的食材组合打上勾。打勾的比例,就是覆盖度量。覆盖率是罕见组合测试中最核心的量化指标。

覆盖率要回答的问题是:在当前覆盖强度目标下,已经覆盖了多少必要值对?它的核心公式非常直观:

覆盖率不只是统计数字,更是定位缺口的探照灯。当覆盖率停在 85% 不再上升,说明剩余未覆盖值对很难被当前生成策略命中,此时需要迭代补充用例——针对缺口定向构造用例,而不是继续盲目扩样本。同时要为项目设定度量基线:比如新模型上线前覆盖率必须 ≥95%,这个基线成为后续回归对照的标尺。老板的“搭配锁定表”越接近满格,他越有底气把隐藏菜单端给顾客;测试的覆盖率越接近目标,团队才越有依据说“罕见组合风险已被系统性排查过”。

Coverage=CcoveredCtotal×100%\displaystyle \text{Coverage} = \frac{C_{\text{covered}}}{C_{\text{total}}} \times 100\%
对 4 参数 3 取值的 pairwise 系统,C_total = 54。覆盖率 80% 意味着还有约 11 个值对从未被任何用例触达——这些未覆盖的点位就是覆盖缺口。
  1. 已覆盖值对数 C_covered当前已执行用例集中,去重后覆盖到的唯一值对数量。同一个值对被多条用例反复命中,也只计一次。
    Ccovered\displaystyle C_{\text{covered}}
  2. 总需覆盖值对数 C_total由覆盖强度决定的值对总量。2-wise 下就是所有交互面的值对之和(此例 54)。
    Ctotal=54\displaystyle C_{\text{total}} = 54
  3. 百分比换算乘以 100% 让覆盖率落在直观的 0–100 区间,便于设定门槛、对比不同批次的进展。

执行监控机制

菜单设计好了,接下来是试吃流水线。老板不会一口气把所有菜同时下锅——厨房会乱,油锅会烧穿。他会分批上菜、记录每道菜的试吃结果、盯住火候防止某道菜煮过头拖垮整场。执行监控机制是对照本:把用例编排成批次、给每个用例设定超时熔断、统一采集日志、实时追踪进度。

批量执行调度解决的是“怎么跑”:把成百上千个用例按照依赖关系和资源配额分片执行,避免一次性压垮评测环境。超时异常管理解决的是“跑挂了怎么办”:某些罕见组合可能让模型陷入死循环或超长推理,必须设置超时阈值,超时就熔断该用例并标记为异常,而不是让它挂死整批任务。日志采集记录则确保每个用例的输入、输出、耗时、异常栈都能回溯——没有日志的失败用例等于没跑过。

执行过程中最重要的量化指标是通过率,它反映当前模型在罕见组合下的整体健康度:

执行监控还强调进度追踪汇报:覆盖率、通过率、剩余用例数、失败分布要像仪表盘一样实时可见,让团队在测试中途就能判断是否有系统性异常——比如覆盖率只涨到 40% 就开始集中失败,往往不是单个 bug,而是某个交互面整体失控。老板盯着试吃流水线,看到某批菜品连续翻车,就知道不是运气问题,而是该停下来研究菜谱了。

Ppass=NpassNtotal×100%\displaystyle P_{\text{pass}} = \frac{N_{\text{pass}}}{N_{\text{total}}} \times 100\%
N_pass 是执行通过的用例数,N_total 是已执行用例总数。通过率 70% 和 99% 代表截然不同的风险等级,也是管理者做上线决策时的硬指标。
  1. 通过用例数 N_pass执行完成后输出符合预期、无异常无超时的用例个数。
    Npass\displaystyle N_{\text{pass}}
  2. 已执行总数 N_total已结束执行(无论通过与否)的用例总数。仍在排队或执行中的用例不计入。
    Ntotal\displaystyle N_{\text{total}}
  3. 通过率换算两者之比乘 100%,得到可以横向对比、纵向追踪的健康度百分比。

结果根因分析

某个隐藏菜单翻车了,客人上吐下泻。老板不会只把菜倒掉就完事,他会追溯:翻车的是哪几种食材的搭配?是食材本身不新鲜,还是配比、火候出了问题?是轻微跑味还是严重到要送医?结果根因分析就是对失败用例的三层深挖:异常结果聚类、失配模式归因、严重度分级。

第一步是异常结果聚类:把所有失败用例按“输入特征+失败症状”分组。如果一批失败用例都集中在上百个“文本长度×编码方式”的罕见组合上,它们大概率共享同一个根因。第二步是失配模式归因:判断失败到底来自“输入组合触发了模型的已知脆弱点”(如对抗性模式),还是来自“测试工具自身的搭配误报”。区分这两者,决定了问题该交给模型团队还是测试基建团队。第三步是严重度分级:致命级(输出违法有害内容)、高危级(功能崩溃不可用)、普通级(输出质量劣化)——分级决定修复优先级和上线决策。

如何量化一个组合是否“特别危险”?可以用该组合子集的异常率与整体基线异常率的差值来衡量:

分析的最后要输出修复建议:将异常聚焦到具体参数组合,指出是模型鲁棒性缺陷、评测用例设计缺陷还是数据标注问题。老板把翻车菜品的配方贴在后厨墙上,标注“不能再碰”,分析团队则把高危组合写进缺陷报告,指引下一步修复方向。

R=fknk−fallnall\displaystyle R = \frac{f_k}{n_k} - \frac{f_{\text{all}}}{n_{\text{all}}}
R 是“风险提升度”:某罕见组合内部异常率相对整体基线的偏离幅度。R=0.3 意味着在这个组合子集里,模型出错的概率比平均高 30 个百分点——这就是需要重点围剿的高危组合。
  1. 子集异常率\frac{f_k}{n_k},其中 f_k 是落在某组合子集 k 内的失败用例数,n_k 是该子集的用例总数。它刻画“这个组合区间的病灶浓度”。
    fknk\displaystyle \frac{f_k}{n_k}
  2. 整体基线异常率\frac{f_{\text{all}}}{n_{\text{all}}},全部已执行用例中失败用例占比,作为全局参照系。
    fallnall\displaystyle \frac{f_{\text{all}}}{n_{\text{all}}}
  3. 差值判定R 越大于 0,说明该组合子集的风险越显著高于平均水平;R≤0 则说明失败是随机的,不必过度关注。

回归体系搭建

隐藏菜单试验成功,老板把十几道稳定菜谱写进“后厨标准手册”:固定食材、固定配比、固定火候。此后每次厨房出新菜,都必须先按手册复验一遍老菜——不能因为新菜火了,老菜却坏了口碑。回归体系搭建就是给 AI 系统立这本“标准手册”。

回归体系的第一块基石是基线回归锁定:把历史测试中确定的高覆盖用例集和覆盖率基线固化为回归套件。每当模型迭代、服务更新,团队都要重新执行这套件,用退化率验证“老毛病没复发”。

除了守住旧基线,回归体系还要做增量覆盖回归:把新发现的高危组合动态补充进回归套件,让基线持续生长。历史缺陷守护则是把过往踩过的每一个“榴莲陷阱”都编码成回归用例,永远不允许它们复活。闭环反馈沉淀把测试发现、修复、回归验证串成一个循环:罕见组合测试不是一次性项目,而是随着模型演进而持续滚动的工作流。

手册越厚,老板越安心;回归基线越全,模型迭代的步伐越稳。罕见组合测试的终点,不是某一次测试跑完,而是一套可持续守护模型安全的常态化机制。

D=1−CregCbase\displaystyle D = 1 - \frac{C_{\text{reg}}}{C_{\text{base}}}
D 是覆盖退化率:回归套件实际覆盖值对数相对锁定基线的损失比例。D=0 表示基线完整保留;D 越大说明新版模型下覆盖流失越严重。
  1. 基线覆盖值对数 C_base锁定回归基线时,套件达到的覆盖值对总数,是后续比对的锚点。
    Cbase\displaystyle C_{\text{base}}
  2. 回归实测覆盖值对数 C_reg某次模型更新后,同一套件实际能覆盖到的值对数量。
    Creg\displaystyle C_{\text{reg}}
  3. 退化率计算1 减去两者比值,得到覆盖率损失的比例。它指导团队判断:覆盖流失是模型行为偏移导致的,还是套件本身需要扩充。

AI 应用场景

智能客服意图识别安全评测

阶段:AI评测与基准测试(测试用例设计与执行)

解决的问题:客服模型上线前,常见问法(“我要退款”“改地址”)都被充分验证,但“方言+否定表达+超长口语化描述”这类罕见组合极易引发意图误判,导致机器人给出错误承诺。传统方式靠人工编例句,覆盖全凭感觉,无法回答“测够了没有”。

具体案例:某电商客服团队对意图分类模型执行 pair wise 组合测试,参数包括语言类型(普通话/粤语/四川话)、语义槽填充方式(完整/省略/指代)、否定表达(无/前置/双重否定)、文本长度(10/200/800 字符)。通过 18 个成对覆盖用例就点亮了全部 54 个值对,发现“四川话+前置否定+长文本”组合下,退款意图被误判为投诉意图,召回率从 92% 骤降到 61%。

大模型 RAG 检索注入防线验证

阶段:边缘用例发现与回归守护

解决的问题:检索增强生成(RAG)系统的风险往往来自低频但致命的组合:恶意注入文本的排版位置、参考文档格式、查询长度、上下文窗口截断方式共同作用,可能绕过安全过滤产生有害输出。单独测每一项都不触发,组合后却失守。

具体案例:某法律咨询 RAG 系统按覆盖基线锁定 128 个值对。一次版本更新后,回归套件实测覆盖率从 100% 退化到 87%,定位发现“Markdown 表格注入 + 长查询 + 文档置顶”的新组合让模型在回答中输出了诱导性条款建议。团队将该组合补入基线,并新生成 6 条增量用例。

自动驾驶感知边缘条件组合

阶段:组合策略生成与结果根因分析

解决的问题:自动驾驶感知模块的输入包括天气、光照、障碍物类型、相对速度等多个维度。真实路测中“大雾+逆光+白色卡车+低速切入”极难偶遇,却是决策系统的致命盲区。

具体案例:测试团队对感知模型构建 5 参数×4 取值的输入空间,用覆盖矩阵生成 45 条成对组合场景送入仿真器。结果聚类发现 3 条失败用例同属“夜间逆光+深色障碍物”交互面,进一步归因确认是图像增强模块的抗噪参数在该组合下失配,提前两周定位了路测无法复现的偶发幽灵刹车问题。

Python 演示

python80 行
import itertoolsimport random class PairwiseTester:    def __init__(self, param_values):        self.param_values = [list(p) for p in param_values]        self.all_cases = list(itertools.product(*self.param_values))        self.pair_list = self._build_pairs()        self.selected = []        self._greedy_cover()     def _build_pairs(self):        pairs = []        k = len(self.param_values)        for i in range(k):            for j in range(i + 1, k):                for x in self.param_values[i]:                    for y in self.param_values[j]:                        pairs.append((i, x, j, y))        return pairs     def _covers(self, case, pair):        i, x, j, y = pair        return case[i] == x and case[j] == y     def _pair_index(self, case, pair):        i, x, j, y = pair        if case[i] == x and case[j] == y:            return True        return False     def _greedy_cover(self):        uncovered = set(range(len(self.pair_list)))        while uncovered:            best_idx = -1            best_gain = -1            for idx, case in enumerate(self.all_cases):                if idx in self.selected:                    continue                gain = sum(1 for pi in uncovered if self._covers(case, self.pair_list[pi]))                if gain > best_gain:                    best_gain = gain                    best_idx = idx            self.selected.append(best_idx)            for pi in list(uncovered):                if self._covers(self.all_cases[best_idx], self.pair_list[pi]):                    uncovered.remove(pi)     def coverage_ratio(self, case_indices):        if not self.pair_list:            return 1.0        covered = set()        for idx in case_indices:            case = self.all_cases[idx]            for pi, pair in enumerate(self.pair_list):                if self._covers(case, pair):                    covered.add(pi)        return len(covered) / len(self.pair_list)  def main():    params = [["晴", "雨", "雪"], ["早", "午", "晚"], ["高", "中", "低"], ["少", "中", "多"]]    tester = PairwiseTester(params)    total = len(tester.all_cases)    selected_n = len(tester.selected)    pairwise_cov = tester.coverage_ratio(tester.selected)    print("参数空间:", params)    print("全组合总数:", total)    print("pairwise 生成用例数:", selected_n)    print("pairwise 覆盖率: {:.1f}%".format(pairwise_cov * 100))    random_idx = [tester.all_cases.index(c) for c in random.sample(tester.all_cases, selected_n)]    random_cov = tester.coverage_ratio(random_idx)    print("同数量随机采样覆盖率: {:.1f}%".format(random_cov * 100))    print("\npairwise 用例列表:")    for idx in tester.selected:        print("  ", tester.all_cases[idx])  if __name__ == "__main__":    main()
目的:用贪心算法生成成对覆盖用例,并量化对比随机采样在相同用例数量下的覆盖率差距,为罕见组合测试的方案选型提供可复现的实验依据。
  1. self.pair_list = self._build_pairs()预先枚举全部两两值对(此例 54 个),作为覆盖目标清单。
  2. def _greedy_cover(self)核心贪心循环:每次从候选全组合里挑出“能覆盖最多未覆盖值对”的一条。
  3. if idx in self.selected跳过已经被选中的用例,避免重复添加同样的完整组合。
  4. gain = sum(1 for pi in uncovered if self._covers(...))统计该候选用例新增覆盖了多少个未覆盖值对。
  5. for pi in list(uncovered)把当前用例覆盖到的值对从待覆盖集合中移除,直到全部覆盖为止。
  6. coverage_ratio()对任意一组用例索引计算去重后的覆盖率,是评估指标的关键工具。
  7. random.sample(tester.all_cases, selected_n)抽取相同数量的随机用例,作为与 pairwise 对比的基线。

常见误区

误区我一直以为测试罕见组合就是挑最大长度、最小温度、最高并发这些极端值跑一遍,把每个参数的极端情况都测到就算覆盖了罕见组合。

正解罕见组合的重点在“组合”而非“单值”。一个由四个完全普通的取值(中等长度、标准编码、正常语气、常规文本)拼成的组合,只要它在整体输入空间中出现的概率足够低,就可能是罕见组合。边界值测试测的是单维度的极端,罕见组合测试测的是多维度交汇的盲区,两者互补而非替代。

为何常见:因为人脑天然倾向于关注“极端”这个显眼特征,却容易忽视“组合概率低”这个更隐蔽的数学属性。

误区只要我用 pairwise 把覆盖率跑到 100%,罕见组合测试就完成了,模型一定不会在组合输入上出问题。

正解pairwise 覆盖的只是“两两交互”这一层保障,三参数甚至四参数交互引发的缺陷依然可能逃逸。此外,覆盖率 100% 只说明值对被执行过,不代表执行结果被正确判定——如果一个高危组合被标记为“通过”但实际输出有害,覆盖率再高也无济于事。覆盖率是必要不充分条件,不是免死金牌。

为何常见:覆盖率是一个直观且令人安心的数字,人们容易把“测过”与“测好”画上等号。

误区既然覆盖率重要,那我不如直接跑全组合,把所有组合都执行一遍,覆盖率 100% 还比 pairwise 更全面。

正解全组合在真实系统中几乎永远不可行——10 个参数各 10 个取值就有 100 亿种组合。更关键的是,组合爆炸带来的执行成本、日志存储和分析噪音会淹没真正重要的信号。pairwise 的意义是在资源约束下取得覆盖率与成本的最佳平衡点,而不是追求字面上的“全部覆盖”。

为何常见:初学组合测试时容易受“完备性”诱惑,忽视了工程现实中的资源边界和收益递减规律。

误区我觉得随机采样更“自然”,能发现成对覆盖想不到的意外组合,所以随机生成大量用例更有效。

正解随机采样最大的问题是覆盖率不可控。由于组合空间巨大,随机样本会大量重复命中高频值对,却系统性遗漏低频值对。实验数据显示,同数量下随机采样的覆盖率往往只有 pairwise 的 60%–80%。随机采样适合作为补充探索,但绝不能替代有覆盖目标驱动的生成策略。

为何常见:随机性给人“不可预测所以更全面”的错觉,但统计学上均匀采样不等于覆盖均匀——组合空间的高维稀疏性让随机命中变得极其低效。

面试题

Q1. 罕见组合测试的核心目标是什么?

单选题 · easy

  • A.验证每个输入参数的取值范围是否合法
  • B.系统性发现低概率输入组合触发的问题← 正确答案
  • C.尽可能多地生成随机输入样本
  • D.提升模型在常见输入下的运行速度

答案:B。罕见组合测试聚焦低概率但高影响的输入组合,B 正确。A 是参数校验而非组合测试;C 只讲数量不讲覆盖;D 是性能优化,与安全测试无关。

Q2. 对 4 个参数各 3 个取值的系统,全组合总数是多少?

单选题 · easy

  • A.共 12 种组合方式
  • B.共 27 种组合方式
  • C.共 81 种组合方式← 正确答案
  • D.共 243 种组合方式

答案:C。全组合数量等于各参数取值数的连乘积。4 个参数均为 3 个取值,N=3×3×3×3=81,选 C。12 错在把 4 和 3 相加;27 错在只算了 3 个参数的连乘;243 是 3 的 5 次方,参数个数数错了。

Q3. pairwise 成对覆盖策略的基本假设是什么?

单选题 · mid

  • A.缺陷主要来源于单个参数的异常取值
  • B.大多数缺陷由两个参数间的交互触发← 正确答案
  • C.三个以上参数交互必定导致缺陷
  • D.组合数量与参数个数呈线性增长关系

答案:B。pairwise 建立在工程经验之上:绝大多数缺陷由两两交互触发,因此覆盖所有值对即可捕获主要风险。A 是单因素测试思路;C 过于绝对且无依据;D 与组合爆炸的指数增长事实完全相反。

Q4. 罕见组合测试设计阶段应包含哪些有效步骤?

多选题 · mid

  • A.划定输入参数的边界和约束范围← 正确答案
  • B.识别参数间可能存在的交互影响← 正确答案
  • C.按业务风险对用例进行优先级排序← 正确答案
  • D.直接上线观察线上用户真实日志

答案:ABC。设计阶段的核心是输入空间建模、交互识别和优先级排序,ABC 都对。D 是线上灰度观察,属于测试后行为或辅助手段,不是测试设计阶段的固有步骤。

Q5. 覆盖率公式 Coverage = C_covered / C_total 中,2-wise 覆盖强度下的 C_total 指什么?

单选题 · mid

  • A.全部笛卡尔积组合的用例总数
  • B.所有两两交互值对去重后的总数← 正确答案
  • C.已经执行过的测试用例总数
  • D.测试过程中发现的缺陷总数

答案:B。C_total 是覆盖目标总量,2-wise 下即所有参数对的值对集合大小。例如 4 参数 3 取值时为 54。A 是全组合用例数 81;C 是已执行样本数,随执行进度变化;D 是缺陷计数,与覆盖目标无关。

Q6. 关于覆盖率100%的理解,下列说法正确的是?

多选题 · hard

  • A.所有目标值对均被至少一个用例执行过← 正确答案
  • B.模型在所有输入组合下绝对安全无风险
  • C.覆盖率可作为识别覆盖缺口的有效工具← 正确答案
  • D.覆盖率是衡量测试质量的唯一核心指标

答案:AC。覆盖率 100% 只代表值对层面的目标已达成,A 对;它不等价于风险清零,因为还有更高阶交互和误判风险,B 错;覆盖率用来检测缺口确实有效,C 对;但它不是唯一指标,执行质量、通过率、根因分析同样关键,D 过于绝对。

Q7. 相比全组合,pairwise 生成用例数量的特点是什么?

单选题 · easy

  • A.数量更大因为覆盖范围更广
  • B.数量明显减少但仍保持两两覆盖← 正确答案
  • C.数量与全组合完全相同
  • D.数量为零因为无法覆盖任何交互

答案:B。pairwise 的价值正是用远少于全组合的用例覆盖所有两两值对。B 正确。A 方向相反;C 混淆了两者规模;D 与 pairwise 的基本功能矛盾。

Q8. 结果分析中风险提升度 R>0 表示什么?

单选题 · hard

  • A.该组合子集的异常率高于整体基线← 正确答案
  • B.该组合子集没有任何风险问题
  • C.当前测试用例样本量不足无法判断
  • D.该组合子集导致覆盖率下降

答案:A。R=f_k/n_k − f_all/n_all,R>0 说明子集异常率高于整体平均,是需要重点围剿的高危组合。B 与公式含义相反;C 是样本量的统计问题,与 R 的计算结果无关;D 混淆了异常率与覆盖率两个维度。

Q9. 搭建罕见组合回归体系时,下列哪些做法是正确的?

多选题 · hard

  • A.锁定历史达成的高覆盖用例集作为基线← 正确答案
  • B.模型每次更新后重新执行回归套件← 正确答案
  • C.将新发现的高危组合增量补入基线← 正确答案
  • D.删除全部历史用例降低维护成本

答案:ABC。基线锁定、回归复测、增量补充是回归体系的三个核心动作,ABC 全对。D 删除历史用例会让基线退化、历史缺陷失去守护,与回归目标背道而驰。

Q10. 执行监控中“超时熔断机制”主要解决什么问题?

单选题 · mid

  • A.测试用例总数过多导致执行队列积压
  • B.单个用例异常挂死拖垮整个批次执行← 正确答案
  • C.日志采集占用过多磁盘空间难以清理
  • D.覆盖率计算缓慢拖慢测试迭代速度

答案:B。某些罕见组合可能触发模型死循环或超长推理,若不设超时阈值,单用例就会挂死整批任务。超时熔断将其标记为异常并继续后续用例。A 是调度问题而非超时问题;C 是日志存储问题;D 是计算性能问题,均与熔断机制的核心职责不符。