技术干货分享:浅谈“MC/DC”


作者:施兰兰(1991-),女,山东人,计算机科学与技术专业硕士,现任北京轩宇信息技术有限公司技术支持工程师,主要负责软件测试工具的售前售后等工作。



单元测试中有三个覆盖率指标,分别是语句覆盖率、分支覆盖率和MC/DC覆盖率,其中MC/DC覆盖率无疑是比较复杂的一项指标,在安全等级较高的软件中,满足MC/DC覆盖是一项强制性要求。那么,到底什么是MC/DC,如何实现MC/DC覆盖,如何利用工具实现MC/DC覆盖测试,让我们带着这些问题一起进入本篇文章的阅读。


01前言


提到单元测试,大家脑海里可能会浮现出“覆盖率”、“功能覆盖”等名词,覆盖率是针对结构测试而言,从被测软件代码的逻辑结构出发设计测试用例,检验标准是语句覆盖率、分支覆盖率和MC/DC覆盖率。与结构测试相对的就是功能测试,功能测试是从被测软件需求出发设计测试用例,检验标准是对需求说明中描述的功能点的覆盖情况。

 

结构覆盖测试是对功能覆盖测试有效的补充,让测试人员更关注软件的实现,检测代码中的每条分支和路径,揭示隐藏在代码中错误,对代码的测试比较彻底。在ISO26262中对软件单元层级提出的结构覆盖标准如图 1所示,从图中可以看出不同安全等级的软件对结构覆盖测试的要求是不一样的,在安全等级为ASILAutomotive Safety Integration LevelD级的软件中,对MC/DC的覆盖测试是强制性的,但是由于其测试的复杂性,缺乏工具辅助,导致在软件测试中对MC/DC覆盖的测试方面做的并不好。下面我们从MC/DC的概念、技术原理和现有解决方案出发对MC/DC覆盖进行详细介绍。

图 1 ISO26262中结构覆盖目标


02什么是MC/DC


MC/DC(修订条件/判定覆盖)(Modified Condition/Decision Coverage)准则作为一种软件结构覆盖率测试准则,已被广泛推广应用于软件验证和测试过程中。该准则在DO-178B(由RTCA/EUROCAE在92年联合颁布的一份针对机载设备的软件开发的指导性文件)中首次提出,目的是为了提高航空软件测试中的覆盖率水平。

 

MC/DC中的条件(Condition)是指由关系操作符构成的布尔表达式,不含任何逻辑操作符;判定(Decision)是指包含逻辑操作符的布尔表达式。例如:

if (A && B) || (A && C)

Statement1

else

Statement2


其中,A,B,C都是一个条件,而(A && B) || (A && C)是一个判定。如果同一个布尔表达式在一个判定中出现多次,那么该表达式应算作多个条件。在(A && B) || (A && C)中,因为布尔表达式A在判定中出现了两次,算作两个条件,所以该判定中共有4个条件。

 

MC/DC的提出是为了引起对布尔表达式的关注,对关键性的实时程序而言,超过半数的可执行代码可能都与布尔运算表达式有关,表达式的复杂性应得到关注。_


03、如何实现MC/DC覆盖


MC/DC适用于一个判定中包含两个及以上条件的情况。MC/DC首先要求实现条件覆盖、分支覆盖,在此基础上,对于每一个条件C,要求存在符合以下条件的两次计算:

1. 条件C所在判定内的所有条件,除条件C外,其他条件的取值完全相同;

2. 条件C的取值相反;

3. 判定的计算结果相反。

 

MC/DC是条件组合覆盖的子集。条件组合覆盖要求覆盖判定中所有条件取值的所有可能组合,需要大量的测试用例,实用性较差。MC/DC具有条件组合覆盖的优势,同时大幅减少用例数。对于一个具有N个条件的布尔表达式,满足条件组合覆盖的用例数则高达2的N次方,而满足MC/DC的用例数下界为N+1,上界为2N。如果条件个数为10,那么满足条件组合覆盖的用例需要2的10次方总计1024个,而满足MC/DC覆盖的用例只需要11至20个,因此选用MC/DC覆盖作为软件测试过程中的一个衡量标准。

 

采用MC/DC最小测试用例集的生成算法设计如下代码段的最小测试用例集见表 1。

if ((A==0 && B==0) || (C==0 && D==0))

int i = 1;

else

int i = 0;

 

通过这种算法生成的最小测试集是不唯一的,因为逻辑表达式运算具有短路效应,因此,此处使用“X”表示条件取“T”“F”都可以的情况。

表 1 MC/DC最小测试集

当测试用例覆盖到一对MC/DC条件组合后,MC/DC覆盖率就会增加25%,所以当用例覆盖到序号1和2时,MC/DC覆盖率为25%,当用例覆盖到序号1、2和3时,MC/DC覆盖率为50%,依此类推,当所有条件组合都覆盖到时,MC/DC覆盖率即可达到100%。


04、案例


在这里选用一个实际案例进一步解释说明,需求描述如下:控制开关状态的变量gEnable,两个控制循环周期的变量cnt1和cnt2,,当gEnable值为1,cnt1大于等于200,cnt2大于等于200时,周期控制变量cnt1和cnt2清零,重新开始周期循环。根据需求,工程师实现部分代码如下。

 

if (gEnable && cnt1 >= 100 && cnt2 >= 100)

{

cnt1 = 0;

cnt2 = 0;

}


现在要对这段代码进行单元测试,如果只进行判定(分支)覆盖测试,通过控制分支中的第一个条件的取值即可满足分支的100%覆盖,如设计用例(0,200,200)和(1,199,200)可分别覆盖判定的“假”分支和“真”分支,即完成了判定覆盖测试,没有任何问题。可是当考虑MC/DC覆盖测试时,需设计用例使3个条件分别独立影响判定结果,根据需求说明我们设计以下用例(见表 2)来满足MC/DC的覆盖。

表 2 MC/DC测试用例表

在实际使用表 2中的用例进行测试时会发现,测试结果并没有达到预期效果,经检查发现代码中的两个条件“cnt1 >= 100”和“cnt2 >= 100”的设计与需求说明不一致,如果只测判定覆盖而不测MC/DC覆盖,是无法发现这个问题的。按照需求说明,应将案例代码进行如下修改,然后根据表 2用例进行测试即可。

if (gEnable && cnt1 >= 200 && cnt2 >= 200)

      {

             cnt1 = 0;

             cnt2 = 0;

      }

05、在SunwiseAUnit中实现MC/DC测试


在上面提到的案例是通过一段简单的代码来说明MC/DC覆盖测试的重要性,在实际软件研制活动中,不仅软件规模庞大,往往留给单元测试的时间非常少,如果完全依靠人工测试,不仅效率低,而且不能保证测试的可靠性和完整性。由北京轩宇信息技术有限公司自主研发的一款可视化自动单元与集成测试平台SunwiseAUnit,不仅支持语句、分支、MC/DC覆盖率的分析与统计,而且可以自动生成MC/DC真值表(如图 2),在MC/DC真值表中可以查看分支详情、已覆盖条件、未覆盖条件、条件组合列表等信息,测试人员可以很清楚的从表格中看出哪些条件组合没有覆盖到,辅助测试人员进行用例设计。SunwiseAUnit采用表格驱动的用例设计界面(见图 3),简单易用,而且在工作界面可以查看MC/DC覆盖率和MC/DC相关的用例以及用例贡献(如图 4)。使用SunwiseAUnit做单元测试,不仅提高测试自动化,而且保证测试的可靠性和完整性,很大程度上降低了人力消耗。


图 2 SunwiseAUnit中的MC/DC真值表

图 3 SunwiseAUnit工作界面

图 4 覆盖率展示


06、小结


作为一种软件结构覆盖率准则,MC/DC要求每一个条件单独影响判定结果,保证了测试充分性。在真实的测试活动中,为提高测试效率就需要借助于单元测试工具,SunwiseAUnit将MC/DC测试技术融入到工具中,在满足测试要求的前提下,减少测试人员的工作量,大大提高测试效率。




-End-




创建时间:2020-02-11 09:40