等价类划分 Equivalence Partitioning

等价类划分可以应用于多个测试层级:

  • 单元测试
  • 集成测试
  • 系统测试

无须自动化工具,相对容易应用

可以灵活调整流程,以获得更多或者更少的测试用例。

输入域

程序的输入域包含该程序所有可能的输入

即使是很小的程序,输入域也大到近乎无穷

测试的本质是从输入域中选取有限的值集合

输入参数定义了输入域的范围,包括:

  • 方法的参数
  • 从文件中读取的数据
  • 全局变量
  • 用户级别的输入

每个输入参数的域被划分为若干区域

从每个区域中至少选取一个值

划分域

划分域

  • 域 D
  • D 的划分方案 p
  • 划分 p 定义了一组块:b₁, b₂, … bₙ
  • 划分必须满足两个性质:
    • 互不相交:各块之间没有重叠
    • 完全覆盖:所有块合在一起覆盖整个域 D

划分域

假设前提 等价性

即同一等价类中的所有值,对于测试目的而言行为相同

两种方法

  • 基于接口的方法
    • 直接从各个输入参数中提取特征
    • 应用最简单
    • 在某些场景下可以部分自动化
  • 基于功能的方法
    • 从被测程序的行为视角提取特征
    • 开发难度更高,需要更多设计工作
    • 可能产生更好的测试,或用更少的测试达到同等效果

基于接口的方法

单独考察每个参数(机械式处理)

这是一种简单的建模技术,主要依赖语法

忽略参数之间的关系

TriTyp 三角形类型判断程序

TriTyp 输入的第一次特征化(TriTyp 有三个整型输入)

TriTyp 第一次输入特征化

TriTyp 输入的第二次特征化

TriTyp 第二次输入特征化

基于功能的方法

  • 识别与预期功能相对应的特征

  • 需要测试人员投入更多设计工作

  • 可以融入领域知识和语义知识

  • 可以利用参数之间的关系

  • 建模可以基于需求而非实现

  • 同一参数可能出现在多个特征中,因此将值转化为测试用例较为困难

以 TriTyp 为例,三个参数代表一个三角形:

合理的特征:三角形的类型

  • 前两种特征化基于语法——参数及其类型
  • 语义层面的特征化可以利用"三个整数代表一个三角形"这一事实

TriTyp输入的几何特征化

初版中"等腰"未排除"等边"的情况,导致块之间存在重叠,不满足互不相交的性质,故需修正。

该划分的取值可选择如下:

几何划分q1的可能取值

分别对应:不等边三角形、等腰非等边、等边三角形、无效(不构成三角形)

边界值分析 Boundary-Value Analysis

等价类的边界处容易存在 Bug。

eg:

float SQRT(float x)
{
   if(x <= 0)
      Error;
   else if(x == 0)
      return 0;
   else {
      // 计算过程
      return result;
   }
}

注意:x<=0 已经覆盖了 x==0 的情况,导致 else if(x==0) 永远不会被执行,这是一个边界处的逻辑错误。

等价类划分:

  • 类(i):x < 0
  • 类(ii):x ≥ 0

边界值:

  • 类(i) 的边界值:0 和 -MAX
  • 类(ii) 的边界值:0 和 +MAX

测试用例:

  • -MAX
  • -MIN
  • 0
  • +MIN
  • +MAX

原本只需 2个 测试用例(覆盖两个等价类),但为了覆盖边界需要额外增加测试。

类型边界测试用例
字符串最短长度-1 / 最大长度+1
示例:长度1~255有效:1个字符、255个字符;无效:0个字符、256个字符
整数MIN-1 / MAX+1
示例:16位无符号整数有效:0、65535;无效:-1、65536
循环循环次数边界
for(int i=0; i<n; ++i)
for(int i=0; i<=n; ++i)
for(int i=1; i<n; ++i)

数值范围参考表

数值范围参考表

字符与 ASCII 码对照表

字符与ASCII

在字符类型的边界值测试中,需关注这些特殊字符的 ASCII 值边界。

选取边界值

对于等价区间为 [Min, Max] 的输入变量,选取以下边界测试点:

选取边界值

选取边界值(双变量示例)

以两个输入变量 x₁(a ≤ x₁ ≤ b)和 x₂(c ≤ x₂ ≤ d)为例,测试用例包括:

选取边界值-双变量示例

核心策略:每次只让一个变量取边界值,其余变量取正常值(Nom)。

数字类型测试用例示例

要求:输入6位正整数,测试用例如下:

数字类型测试用例示例

弱边界分析 Weak Boundary Analysis

策略:每次只让一个变量处于边界,仅考虑有效边界值(不含无效值),测试用例数量较少。

选取边界值(含无效值)

对于等价区间为 [Min, Max] 的输入变量,增加无效边界点后选取:

选取边界值-含无效值

弱健壮边界分析 Weak Robust-Boundary Analysis

以两个输入变量 x₁(a ≤ x₁ ≤ b)和 x₂(c ≤ x₂ ≤ d)为例:

弱健壮边界分析

TriTyp 的边界分析

TriTyp(a, b, c),约束条件:

  • 1 ≤ a ≤ 100
  • 1 ≤ b ≤ 100
  • 1 ≤ c ≤ 100
变量测试取值集合
a{0, 1, 2, 50, 99, 100, 101}
b{0, 1, 2, 50, 99, 100, 101}
c{0, 1, 2, 50, 99, 100, 101}

包含 Min-(0)、Min(1)、Min+(2)、Nom(50)、Max-(99)、Max(100)、Max+(101)七个测试点。

NextDate 的边界分析

月份范围:[1, 12]

日期范围(按月份):

月份日期范围
1、3、5、7、8、10、12月[1,31]
4、6、9、11月[1,30]
平年2月[1, 28]
闰年2月[1, 29]

强边界分析 Strong Boundary Analysis

策略:对所有变量的边界值取笛卡尔积,即每个变量都同时取所有边界点,测试用例数量远多于弱边界分析。

TriTyp 的强边界分析

TriTyp(a, b, c),约束条件:

  • 1 ≤ a ≤ 100
  • 1 ≤ b ≤ 100
  • 1 ≤ c ≤ 100
变量测试取值集合
a{ 1, 2, 50, 99, 100}
b{ 1, 2, 50, 99, 100}
c{ 1, 2, 50, 99, 100}

测试集合 = a × b × c = {1, 2, 50, 99, 100} × {1, 2, 50, 99, 100} × {1, 2, 50, 99, 100}

共 5 × 5 × 5 = 125 个测试用例。

强健壮边界分析 Strong Robust-Boundary Analysis

以两个输入变量 x₁(a ≤ x₁ ≤ b)和 x₂(c ≤ x₂ ≤ d)为例:

在强边界分析基础上,同时加入无效边界值(Min- 和 Max+),并对所有变量取笛卡尔积。

强健壮边界分析

测试用例数量最多,覆盖最全面,但成本也最高。

NextDate 的边界分析 (强边界)

NextDate(Day, Month, Year),约束条件:

  • 1 ≤ day ≤ 31
  • 1 ≤ month ≤ 12
  • 1900 ≤ year ≤ 2012

NextDate

每个变量包含 Min-、Min、Min+、Nom、Max-、Max、Max+ 共7个测试点。

边界知识小结

概念含义
Boundary(边界)等价类之间的分界线/分界点
Boundary Values(边界值)位于边界附近的具体取值(Min、Max 等)
Boundary Analysis(边界分析)系统地选取边界值作为测试用例的方法

组合测试预热 Combinatorial Testing

回顾:输入域测试方法

  • 随机测试(Random Testing)
  • 等价类划分(Equivalence Partitioning)
  • 边界值分析(Boundary-Value Analysis)

当前的问题:上述方法未能有效处理输入变量之间的关系。

回顾:基于模型的测试

决策表测试(Decision Tables)

  • 能够考虑输入变量与输出变量之间的关系
  • 问题:难度较大
    • 提取变量间关系本身就很困难
    • 如何描述这些关系也是一大挑战

弱等价类测试 Weak Equivalence Class Testing

弱等价类测试

弱等价类测试:用最少的测试用例覆盖所有等价类,不做笛卡尔积。

强等价类测试 Strong Equivalence Class Testing

  • X: 3个等价类
  • Y: 4个等价类

测试策略:对所有等价类取笛卡尔积,测试用例数 = 3 × 4 = 12个

覆盖 X 和 Y 每个等价类的所有组合,测试更充分但成本更高。

坐标示意图中:X 轴分为 [1,5)、[5,10)、[10,20) 三类;Y 轴分为 [1,10)、[10,20)、[20,30)、[30,+) 四类。

高性价比测试 Cost Effective Testing

  • 强等价类测试(笛卡尔积)覆盖全面,但测试用例数量爆炸式增长
  • 弱等价类测试用例少,但可能遗漏变量间的交互缺陷
  • 如何在测试成本与缺陷检测能力之间取得平衡?

组合测试示例

有4个输入,各自的等价类:

组合测试示例

弱等价类测试 取 max = 3 个测试用例

弱等价类测试

每个等价类至少出现一次,用例数 = max(2, 2, 2, 3) = 3个,但变量间的组合关系未被充分覆盖。

组合测试 Combinatorial Testing

核心思想:通过系统地组合输入变量的各等价类值,在有限的测试用例中尽可能覆盖变量间的交互关系。

全组合测试 All Combinations

对所有参数值的可能组合全部测试:

全组合测试

总测试用例数 = 2 × 2 × 2 × 3 = 24个

覆盖最全面,但成本极高,实际项目中几乎不可行。

全组合测试用例完整列表

A1组(12个):

A1组

A2组(12个):

A2组

成对测试 Pair-wise Testing

策略:确保任意两个输入变量的所有取值组合至少出现一次,大幅减少测试用例数量。

仅需 6个 测试用例:

成对测试

从24个减少到6个,覆盖了所有两两组合,性价比极高。

t-wise / t-ways 组合测试

策略:确保任意 t 个输入变量的所有取值组合至少出现一次。

当 t = 3 时,需要 12个 测试用例:

t-wise

t 值越大,覆盖越全面,用例数越多(介于成对测试和全组合之间)。

组合测试方法汇总

组合测试
├── 固定强度组合测试(Fixed Strength)
│   ├── 成对测试(Pair-wise,t=2)
│   └── t-way 组合测试(t=3, 4, ...)
└── 可变强度组合测试(Variable Strength)

核心问题:

  • 在全组合中进行采样
  • 不考虑输入变量的特殊信息(即把所有变量一视同仁)

可变强度组合测试 Variable Strength Combinatorial Testing

核心思想:根据实际情况,对不同的变量组合设定不同的覆盖强度。

交互关系定义:

R = { {Input A, Input B, Input C},
      {Input A, Input D},
      {Input C, Input D} }

即:A+B+C 之间需做3-wise覆盖,A+D 之间需做2-wise,C+D 之间需做2-wise。

生成的测试用例(9个):

可变强度组合测试

比固定强度的12个用例少,同时针对重点变量组合做了更有针对性的覆盖。