[名词解释]MC/DC
SQLite 的作者 Dr. D. Richard Hipp 在 Hacker News 讨论了自己对于 SQLite 测试相关的看法:
关于测试覆盖度,最常见的标准称为 “modified condition/decison coverage” 或 MC / DC。在像 C语言中,MC / DC 和分支覆盖虽然不完全相同,但非常接近。
达成 100% MC / DC 并不能证明你总能得到正确的答案。这意味着你的测试非常完善,以至于你设法让每个机器代码分支至少在两个方向上进行。这是一个高标准,很难实现。这并不意味着该软件是完美的。
但它确实有帮助,而且很大。当我年轻的时候,我曾经认为我可以完美无瑕的代码。然后我写了 SQLite,它被许多应用程序拾起并使用。当你的代码在数十亿台设备上的数百万应用程序中运行时,会出现多少问题。
SQLite 获得源源不断的错误报告。然后我花了 10个月(2008-09-25 到 2009-07-25)为 SQLite 编写了 100% 的 MC / DC 测试。之后,错误报告的数量减慢到了涓涓细流。还有 bug。但是 bug 的数量大大减少了。100% MC / DC 最初是在 2009-07-25 达成的,但是工作并没有就此结束。我花费了大部分开发时间来添加和增强测试用例,以跟上可交付的 SQLite 代码的变化。
100%MC / DC只是一个阈值,一个很高的阈值,一个易于测量且难以作弊的门槛。但它只是我们说“足够”的门槛。你可以轻松选择不同的阈值,例如 100% 行覆盖率。阈值越高,错误越少。但只要项目足够的大,它总会有错误。
我的经验是,你最终必须编写的奇怪测试只是为了让一些不起眼的分支以某种方式走向最终在系统中完全不相关的部分并发现问题。 100%MC / DC 的主要好处之一并不是每个分支都经过测试,而是你必须编写如此多的测试:随机的、古怪的、错综复杂的……然后你就可以发现问题,并修复了许多你从未想过的问题。
100%MC / DC 的另一大优势是,一旦它们到位,你可以在代码中的任何地方进行任何更改,如果测试仍然通过,你就会非常自信地没有破坏任何东西。这使我们能够以相对较少的逐行检查,更快地演进 SQLite 代码。
100%MC / DC 的另一个优点是你真的在测试编译的机器代码,而不是源代码。所以你不用担心编译器错误。UB(Undefined Behavior)是 C 的一个大问题。即使官方的 C 语言规范不强制要求没有 UB,我们仍然避免使用 UB。据我们所知,SQLite目前不包含任何 UB,这也就给了我们信心编译器的结果一定是我们想要的结果。如果你发现了 SQLite 的 UB,请一定告诉我们 :-)
MC/DC(修订的条件/分支软件测试)准则是一种实用的软件结构软件测试率软件测试准则,已被广泛应用于软件验证和软件测试过程中。
案例2-19:MC/DC覆盖测试。
condition和decision的概念:
if (A || B && C ) { 语句1; } Else{ 语句2; }
A,B,C都是一个条件,而(A || B && C)叫一个Decision,如果是条件软件测试,只需两个CASE,就能软件测试,就是让这个decision为True和False各一次,就能达到。即:
A=True、B=False、C=True。
A=False、B=True、C=False。
如果是MC/DC,就得4个测试用例,怎么计算呢?
MC/DC覆盖测试在每个判定中的每个条件都曾独立影响判定的结果至少一次(独立影响意思是在其他条件不变的情况下,改变一个条件):
A || B && C
总结:每个条件对结果都独立起作用。
(1)如果A对结果起作用的话,B必须为False、C必须为True,这样结果就独立受A的值影响。(A||0&&1)->(A||0),(A、B、C取值分别为A=True、B=False、C=True和A=False、B=False、C=True)。
(2)同理,如果B对结果独立起作用,A必须为False、C必须为True,两种情况B为True、False各一个 (0||B&&1) (A、B、C取值分别为A=False、B=True、C=True和A=False、B=False、C=True)。
(3)如果C独立对结果起作用,就是让(A || B) 为True,为了减少用例,上面的用例已经含有这样的用例了,就取A为False、B为True,这样C独立起作用的用例为 (0||1&&C)->(1&&C)。(A、B、C取值分别为A=False、B=True、C=True和A=False、B=True、C=False)。
可以看出,每个条件各走了一次True和False,这样3个变量条件就会有6个用例, 但是其中里面有两个是重复的。
在1、2情形中均出现A=False、B=False、C=True。
在2、3情形中均出现A=False、B=True、C=True。
因此,***的测试用例为。
A=True、B=False、C=True。
A=False、B=False、C=True。
A=False、B=True、C=True。
A= False、B=True、C=False。
需要进一步补充说明的是,MC/DC测试的主要目的是为了防止在组合条件表达式中包含副作用(side effect),见以下语句:
if (a() || b() || c()){ ... }
当b函数或c函数产生副作用时,MC/DC软件测试存在非常大的必要性。
原则上不应在组合条件表达式中调用产生副作用的函数。
参考:
MC/DC(修订的条件/分支软件测试)覆盖测试 - https://book.51cto.com/art/201708/549277.htm
如何看待sqlite作者放弃sqlite4的开发,说使用LSM Tree是一种失败? - https://www.zhihu.com/question/67858225/answer/632339756