行覆盖率

1.std::string/std::vector默认初始化导致行覆盖不上,请使用有参数初始化。

std::string camera_model_name;//不能行覆盖
 
std::vector<double_t> r_s2b_vec;//不能行覆盖

std::string camera_model_name{""};//行覆盖,但产生两个分支,仅覆盖1个
 
std::vector<double_t> r_s2b_vec{0LU};//行覆盖,但产生两个分支,仅覆盖1个

2.param omp可能导致无法覆盖

尽量不要使用

#pragma omp parallel for

可能导致之后的for循环无法行覆盖。

分支覆盖率

产生分支的前提为该行已覆盖。 

HOW TO提高分支覆盖率?--面向高覆盖率编程

  1. 避免抛出异常

其中,一可以通过增加测试用例来覆盖,二-七部分系gcc抛出异常导致,可以通过编译选项添加-fno-exceptions。但如果使用try-catch,那么编译不通过。

不添加-fno-exceptions:

lcov覆盖率进阶:提高分支覆盖率技巧_c++

添加-fno-exceptions:

lcov覆盖率进阶:提高分支覆盖率技巧_c++_02

上图展示了部分带有抛出异常的分支场景,包括printf/cout/string初始化/new/delete等,除delete[]外,通过关闭抛出异常,都不再产生额外分支。

2. 逻辑判断分支产生场景分析

lcov覆盖率进阶:提高分支覆盖率技巧_函数调用_03

1.if(condition) 如果条件为单独条件,那么会有两个分支,并只会覆盖其中一个。

2.for /while 除非初始判断就不满足,(即若p2 <0时),只会覆盖一个分支,其他情况执行循环体时两个分支都自动覆盖。

3.条件运算符 同if

4. 子条件复合

lcov覆盖率进阶:提高分支覆盖率技巧_初始化_04

子条件复合时,会从左到右覆盖,如果满足一定条件时剩下分支不会覆盖。例如多个条件的或时,只要有个条件为true,其右侧分支不再覆盖,产生两个未覆盖分支,与操作的false同理。

lcov覆盖率进阶:提高分支覆盖率技巧_初始化_05

单条件结果赋值时不会产生分支。

return 同理。

3. 简洁的子条件

尽量减少在判断中出现函数调用,以避免出现难以覆盖的新的分支。

lcov覆盖率进阶:提高分支覆盖率技巧_函数调用_06

如图所示,直接在判断中调用abs会多出两个分支,因次推荐子条件简洁化

lcov覆盖率进阶:提高分支覆盖率技巧_抛出异常_07

函数调用与函数本身有无判断并不关,凡是多条件中产生函数调用均会产生两个分支,但多条件多次调用不会增加。

4.逻辑简单

尽量减少无意义的判断,或代码逻辑上不可能发生另一分支的情况

lcov覆盖率进阶:提高分支覆盖率技巧_函数调用_08

lcov覆盖率进阶:提高分支覆盖率技巧_初始化_09

lcov覆盖率进阶:提高分支覆盖率技巧_分支覆盖_10

5. 拒绝用宏

尽量不要使用宏。

MCAM_SAFE_LOAD_PARAM:3/16

108 [ + - ][ + - ]: 10 : MCAM_SAFE_LOAD_PARAM(cameraSettings, "kc5", p.arr[j]);
[ + - ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]

6.switch-case 与 if - else 的抉择

switch-case 共产生n+1个分支(n:case数量 1:default),但是一个样例只能覆盖1个分支,此处分支覆盖率1/(n+1)。

if-elseif 共2*n个分支,覆盖数视样例而定,最低1个,即第一if满足,最高n个,即前n-1个if elseif不满足,最后一个elseif满足。所以分支覆盖率1/(2n)~1/2。均值(n+1)/(4n)。

所以在仅有一个样例的情况下if else的分支覆盖率更高,(除非switch case漏了break)但实现分支全覆盖,都需要n个测试样例。

尽量不使用switch-case,改用if-else能够使分支覆盖率更高效。特别地,在对enum值的范围明确的情况下,如果不设置default值,那么会多一个无法覆盖的分支,并且if else if else可以减少两个分支的出现,即将最后一个取值设为else。

lcov覆盖率进阶:提高分支覆盖率技巧_函数调用_11

 测试用例见GitHub - typeisgod/gcov