如果现成的测试充分准则里面找不到可用的,我们可能就需要自己来创立一个新的准则。我们不知道历史上第一个面对深度神经网络系统的测试工程师是谁,但我们知道他在做测试设计的时候,肯定遇到过这个问题:现成的控制流覆盖准则或数据流覆盖准则都不能用,因为深度神经网络系统不同于传统的软件,它的结构要素不再是代码行或者变量的定义使用。这位工程师只能依靠准则化的思想,自己创立一个新的准则,比如我们现在所熟知的“神经元覆盖准则”。
要创立一个准则,我们需要做两件事:
① 建立价值观,也就是识别测试焦点,明确测试目标;
② 将价值观准则化,也就是设计一种具体的形式来约束和评价测试集,以实现测试目标。
准则的具体形式,包括判定型和度量型两种。判定型准则回答的问题是 ,一个测试集充分还是不充分:
度量型准则回答的问题是,一个测试集的充分度是多少:
显然,判定型准则可以看做是度量型准则的一种特殊情况:
比如,“语句覆盖率”是度量型准则,而“要求语句覆盖率达到100%”,就是判定型准则;再比如,“变异得分”是度量型准则,而“要求变异得分达到1”就是判定型准则。
自己创立一个测试充分准则——这件事听起来貌似很高大上,其实离我们并不遥远。在我们的日常测试工作中,我们经常在做这件事——我们经常会想:“好,测了这些用例应该就差不多了”。这种想法,其实就来自我们内心已经建立起的一些模糊的准则。
当然这种准则可能并不严谨,也不能通用。如果我们想提出一些高水平的准则,能够对测试充分性进行比较科学的度量,能在高级别的期刊会议上发表,得到业界的认可和推广,我们就需要在设计准则的时候,尽可能让它具备这样一些优良的性质:
我们用“变异得分”这个准则来解释一下这些性质:
① 归一性。意思是,准则给出的测试充分度结果,取值应在[0, 1]之间。同时,空集的测试充分度应为0,穷尽测试集的测试充分度应为1——变异得分是刨除等价变异体之后,被杀死的变异体占变异体总数的比例,所以取值一定在[0, 1]之间。如果测试集为空,肯定不能杀死任何变异体,变异得分是0;如果是穷尽测试集,肯定就能杀死等价变异体之外的所有变异体,变异得分就是1。
② 有限适用性。意思是,一定存在一个有限的测试集,能够满足给定的充分度指标——假设给定的变异得分指标是1,那是不是一定存在一个有限的测试集,能杀死所有非等价变异体呢?是的,因为如果一个变异体不是等价变异体,那就一定能找到一个用例杀死这个变异体。变异体的数量是有限的,所以需要的用例数量就是有限的。
③ 单调性。意思是,如果在测试集中补充了新的用例,测试集的充分度会提高,至少不会降低——补充用例,就有可能杀死更多的变异体,变异得分只会提高不会降低。
④ 次可加性。意思是,多个测试集的并集的充分度,不应该高于其各自充分度的加和——假设一共有5个非等价变异体A/B/C/D/E,测试集T1能杀死A和B,测试集T2能杀死B和C:
那么,T1的变异得分就是0.4,T2的变异得分也是0.4。而T1∪T2的变异得分是0.6,比T1和T2各自变异得分的加和要小。
⑤ 贡献递减性。意思是,已经完成的测试越多,接下来补充的测试对充分性的贡献就越小——假设还有一个测试集T3,能杀死C和D:
考虑两种情况。第一种情况是,先执行T1,执行完之后变异得分是0.4,然后执行T3,这时候变异得分会增加0.4;另一种情况是,先执行T1和T2,执行完之后变异得分是0.6,然后执行T3,这时候变异得分只会增加0.2。这就是贡献递减性。