3. 测试用例设计基础

数值算法的测试用例不是“随便找几个数跑一跑”,而是一份可复现的验证契约:它必须说明测什么、用什么输入、期望什么输出、在什么容差下判定通过。理解测试用例的构成要素,是后续所有验证工作的起点。

一、测试用例的构成要素

一条完整的数值算法测试用例通常包含六个要素:用例标识(唯一编号,便于追溯)、被测对象(具体函数、模块或算法分支)、输入数据(参数值、初值、矩阵、区间端点等)、前置条件(如迭代初值、收敛阈值、浮点环境设置)、期望结果(解析解、高精度参考值或满足的性质)、判定准则(绝对误差、相对误差、残差范数或性质是否成立)。其中判定准则最容易被忽视——数值结果几乎不会逐位相等,必须事先约定“多接近才算对”。

例如测试一个求根函数 bisect(f, a, b, tol),输入可取 f(x)=x^3-x-2、区间 [1,2]、容差 1e-10;期望结果可写为“根约 1.5213797068”;判定准则写为“|x*−x_ref| ≤ 1e-8 且 |f(x*)| ≤ 1e-10”。这样即使实现细节不同,只要满足准则即可判通过。

二、黑盒与白盒思想在数值算法中的适用性

黑盒测试只关心输入与输出的映射关系,不查看内部实现。它适合验证算法的外部契约:给定合法输入是否返回满足精度要求的结果、非法输入是否被正确拒绝、边界输入是否稳定。数值算法中,黑盒用例便于在重构、换语言、换编译器后复用。

白盒测试依据内部结构设计用例,追求语句、分支、路径覆盖。数值算法的白盒价值集中在分支与异常路径:如迭代是否收敛的两条出口、除零保护、矩阵奇异判定、区间端点函数值异号检查等。但纯粹的路径覆盖对数值算法帮助有限——浮点运算的组合爆炸使全覆盖不可行,且很多缺陷表现为精度退化而非分支错误。实践中应以黑盒为主、白盒为辅:黑盒保证结果正确性,白盒保证关键分支和防御逻辑被执行到。

数值算法测试用例设计:从输入空间到判定 输入空间划分 有效等价类 合法区间、正常量级 无效等价类 越界、类型错误 边界值 端点、零、极值附近 病态/特殊值 NaN、Inf、近奇异 测试策略 黑盒:外部契约 输入→输出映射、精度 重构后可复用 白盒:内部路径 收敛/不收敛分支 除零、奇异、防御逻辑 数值特殊考量 容差判定、条件数 舍入、迭代次数上限 判定与输出 绝对/相对误差 |x−x_ref| ≤ tol 残差范数 ‖Ax−b‖ ≤ ε 性质断言 单调性、对称性、守恒 通过 / 失败 / 待查

三、等价类划分与边界值分析

等价类划分把输入空间切成若干子集,认为同一子集内任一输入暴露缺陷的能力相近,因此每类取少量代表即可。对数值算法,划分维度往往不止一个:按数值范围(如容差 tol 取 1e-3、1e-8、1e-12)、按问题规模(n=1、n=100、n=10000)、按数据性质(良态/病态、对称/非对称、稀疏/稠密)分别划分,再组合成用例。

边界值分析针对等价类的边缘取值。数值算法的边界尤其危险:区间端点处函数值恰为零、容差取机器精度量级、矩阵接近奇异、迭代次数刚好达到上限。以二分法为例,除常规区间 [1,2] 外,应补充:端点即根(f(a)=0)、区间极窄(b−a 接近容差)、f(a) 与 f(b) 同号(应报错)等用例。这些正是缺陷高发处。

四、数值算法测试用例设计的特殊考量

判定必须带容差。浮点运算不满足结合律,同一算法不同实现可能末位不同。用例应写明误差类型与阈值,并区分“结果误差”与“残差”:线性方程组求解中,残差小不代表解准,病态矩阵下二者可能相差数量级,必要时同时断言两者。

参考值来源要可靠。期望结果可来自解析解、高精度库(如 mpmath 计算到 50 位)、已知性质的构造解,或多种独立算法交叉验证。切忌用被测实现自身生成期望值,那会形成循环论证。

覆盖数值退化与异常。应显式设计 NaN/Inf 输入、上溢下溢、除零、不收敛、迭代上限触发等用例,并明确期望行为是“返回错误码”还是“抛出异常”,而非笼统地“不崩溃”。

记录可复现信息。浮点结果依赖编译器优化、FMA 使用、舍入模式与并行归约顺序。用例应固定并记录这些环境条件,否则“时过时不过”的偶发失败难以定位。

设计数值用例时,先问三个问题:这个输入的“正确答案”从哪来?允许多大误差?如果实现有 bug,最可能在哪类输入上暴露?三问的答案基本就决定了用例集合的骨架。

把上述要素落到一份可执行的用例表,是本节最直接的交付物。下表以一个“一维求根”被测对象为例,展示等价类、边界值与特殊值如何共同构成用例集(数值为教学示例,非实测结果):

编号类别输入期望/判定
R-01有效等价类f=x³−x−2, [1,2], tol=1e-10|x*−1.5213797068|≤1e-8
R-02边界:端点即根f=x−1, [1,3]x*=1,误差≤1e-12
R-03边界:区间极窄[1.5,1.5+1e-12]正常返回或明确报错
R-04无效等价类f(a)、f(b) 同号抛出区间无效异常
R-05特殊值f 返回 NaN检测并报错,不静默循环
R-06白盒分支迭代上限设为 3触发“未收敛”出口

这张表的价值在于:每条用例都有明确的判定依据,任何人按表执行都能得到一致结论。测试用例设计的本质,就是把“我觉得应该对”转化为“在约定条件下可判定对错”的可复现证据。