作者 | 李伟 上海控安安全测评部总监
来源 | 鉴源实验室
社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区”
引言: 上一篇开始我们介绍白盒的代码结构覆盖率测试,已经完成了语句覆盖测试的讲解,本篇我们介绍分支覆盖。
01
关于定义
从测试技术对代码的测试程度上来说,在复杂代码中,分支覆盖比语句覆盖效果要好。很多时候分支覆盖也被叫做判定覆盖。语句覆盖是要求设计的测试用例可以让所有的语句都能够被执行测试。分支覆盖是要求设计用例对代码中所有的逻辑判定分支都被执行测试,也就是每次判定逻辑上真假两种的分支执行情况都覆盖。从定义上我们就可以看出两种方法的测试度量角度是不一样的。计算方法上,语句覆盖的分母是代码总行数,分支覆盖的分母是代码中所有判断的分支总数。
02
分支覆盖测试的举例
我们使用下面一段简单代码来举例说明:
这段代码总共11行,一个逻辑判断的条件,即x<10为真或假,我们可以看到输入的变量a和b决定了输出值y。对于这段代码的分支覆盖测试设计,我们令a=5或a=15,对应x<10为真或假两种情况。a=5时x<10为真,测试用例执行了代码的第1-6行进入了逻辑真的分支,a=15时x<10为假,代码执行了第1、2和8至11行,执行了逻辑为假的分支。这两条测试用例覆盖全部的两个判定分支,分支覆盖率为100%。
这上面这段代码中,我们针对分支覆盖设计了两条测试用例,达到了覆盖率100%,我们可以发现同样是这两条测试设计,语句覆盖率一样达到了100%,那语句覆盖跟分支覆盖的区别如何体现呢,同样是这段代码我们实际中很多时候是用下面的习惯编写,如:
这段代码的效果跟前面举例中代码的效果是一样的,对于分支覆盖设计也是一样,因为同样只有一个判定条件,需要分别测试x<10为真或假的两种分支情况,但是语句覆盖设计就不一样了,语句覆盖设计只需要设计一条用例,令a=5即可以覆盖所有的代码语句。这里我们就可以看出分支覆盖的结构化程度高于语句覆盖。
上面的例子相对简单,我们把这段代码稍微变动,来深入探讨一下分支覆盖。示例代码如下:
我们可以看到这段代码的逻辑判断了一次,代码同样有两个分支,针对分支覆盖测试我们只需要针对x < 10 && y > 10 == 0 为真或假两种情况,即我们可以令a=15或b=5时代码判断进入条件真的分支,令a=5且b=15代码判断进入条件假的分支。
上面的例子我们也可以看出,分支覆盖测试我们仅在if后面的整体判定语句上取了真和假两种情况,并未深入到该行代码语句中每个判定条件来取真假。
03
使用工具来进行分支覆盖测试
本章节我们继续使用SmartRocket TestGrid这款工具进行代码的分支覆盖测试分析,给大家介绍工具是如何生成测试用例完成测试任务的。
3.1 工具测试举例
针对如下代码:
这段代码我们可以看到函数的形参有两个,分别是lua_State *L、init idx,代码逻辑也较为简单,当more为真时执行api_incr_top(L),为假时执行L->top -= 1。more为代码块中定义的局部变量,被赋值为luaH_next(L, hvalue(t), L->top - 1)。
工具自动分析后会生产控制流图如下:
控制流图可以直观地看到在本例中两条分支情况,我们可以设计测试用例令more分别为真和假,分别覆盖两条分支,这样就可以完成分支100%覆盖。
我们通过查看项目头文件可以得到函数luaH_next()的形参hvalue(t)已有定义,通过宏替换变为luaH_next (L, ((&((((union GCUnion *)((((t)->value_).gc))))->h))), L->top - 1),可以通过工具来生成用例中的桩函数,下图为工具自动生成的测试用例1:
本条用例中桩函数的返回值控制了判断条件的真或假,本条测试用例覆盖的是代码中为真的分支语句。代码中函数的最终返回值也是由more变量决定,我们在用例的输出也可以看到实际返回值跟桩函数的返回值是一样的。
下图为测试用例2:
本例中桩函数luaH_next()的返回值设置为0,所以覆盖的是代码中判断结果为假语句分支代码。对于用例中的输入形参,在执行过程中影响了桩函数和执行语句,间接影响本例中的判断条件取值。
我们可以看到工具通过这两条测试用例分别覆盖了两个判断的分支,所以这段代码的测试分支覆盖率就是100%。
04
测试小结
在执行分支覆盖测试时我们有以下建议供大家参考。
1. 通常sil等级不同要求执行的结构覆盖方法会不一样,但是语句覆盖通常会和分支覆盖一起出现在低sil等级的测试要求中。
2. 语句覆盖和分支覆盖的覆盖率统计维度是不一样的,语句覆盖是以代码行数为分母,分支覆盖是以代码中逻辑判断的分支总数为分母。
3. 在合并执行语句覆盖和分支覆盖时测试用例是可以复用的,我们可以在语句覆盖的基础上叠加用例来完成未被测试的分支部分覆盖。