lcov分支覆盖率的分析和总结

覆盖率显示规则

一行从左到右分别万代表:

1.代码行号(空白代表分支显示不过来产生换行)

2.分支覆盖情况 3.该行调用次数 4.该行源代码以及行覆盖情况

lcov分支覆盖率的分析和总结_第1张图片

其中,分支覆盖情况详细介绍如下:

中括号代表生成的一对子分支,+代表该子分支被覆盖,-代表该子分支未覆盖,但对应的另一分支被覆盖,#代表两个子分支均未被覆盖。

以if(condition)为例,如果该condition没有子条件,即不是其他条件"与"、"或"产生,那么会产生两个分支,即condition == true condition == false,若只能满足condition == true 或false,则分支覆盖结果为[+ -]或[- +],如果多次调用时condition == true 或false都能满足,则分支覆盖结果为[+ +]。如果condition == true或false都不能发生,那么覆盖结果为[# #](虽然在最简单的条件下这个结果并不会发生)。

行覆盖情况详细介绍如下:

如果该行代码被覆盖到,则其底色为蓝色,没有被覆盖到,则底色为蓝色,若该行是上一行代码的续行,或为return 语句、class声明等,其底色为白色,代表不会进行检测。注意,没有被覆盖的行不会产生分支。

除了常见的逻辑判断外,还有很多产生分支的情况,并且难以完全覆盖,总结如下:

一、 常见逻辑判断

1. if (condition1) - elseif (condition2) - else [if(true)和if(false)除外]

2. for(init;condition/incre)/while(condition) [while(true)、while(false)和for(init;;incre)等没有条件判断除外]

3.条件运算符 condition ? exp1 : exp2

4.switch - case

5.多条件的与或。常见的为return (mulit-condition) ,例如return (x==0 || x==1)。

二、空间/文件管理操作

解析:可能存在操作没有权限、内存分配失败等情况。

1. new /delete 操作符

2. 文件操作:打开、关闭、输出等

例如

cv::FileStorage cameraSettings{std::string(camera_file), cv::FileStorage::READ};
cameraSettings.isOpened()

cameraSettings.close()

以及fprintf等。

3.memcpy

三、宏/内联函数自带的判断

如果宏/内联函数声明中自带判断,那么预处理时会在调用处原地展开,最好的做法是用普通函数代替宏/内联函数,这样不会在每个调用的代码段都产生分支。

四、字符串转换

1.char *到String类

String类的构造函数如下:(加粗部分含有判断)

basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())

      : _M_dataplus(_M_local_data(), __a)

      { _M_construct(__s, __s ? __s + traits_type::length(__s) : __s+npos); }

char *转String时会判断char *是否为nullptr,即自带一个判断。

2.String类到char *

与char *到String类相似。

五、类成员函数调用

即使成员函数内部没有判断,也没有返回值。

六、cpp文件末尾。

七、其他库函数调用。

但是一般情况下只能使用测试样例实现对常见逻辑判断的覆盖,以及使用普通函数代替宏或者内联函数来提高分支覆盖率,其他情况下不能覆盖,只能给予说明。

复杂情形:

一、

if ((std::abs(p.arr[2]) < 1e-10) 
&& (std::abs(p.arr[3]) < 1e-10) 
&& (std::abs(p.arr[4]) < 1e-10) 
&&(std::abs(p.arr[5]) < 1e-10))

该判断共四个子条件,但lcov显示共10个分支,包括四个子条件分别成立和不成立,共八个分支,外加总条件,即这些子条件的与的成立和不成立两个条件,共十个分支:

  1. std::abs(p.arr[2]) < 1e-10 成立
  2. std::abs(p.arr[2]) < 1e-10 不成立
  3. std::abs(p.arr[3]) < 1e-10 成立
  4. std::abs(p.arr[3]) < 1e-10 不成立
  5. std::abs(p.arr[4]) < 1e-10 成立
  6. std::abs(p.arr[4]) < 1e-10 不成立
  7. std::abs(p.arr[5]) < 1e-10 成立
  8. std::abs(p.arr[5]) < 1e-10 不成立
  9. std::abs产生,不明
  10. std::abs产生,不明

二、

if ((!load_with_general_format) &&       
loadCameraModelParametersWithSVFormat(
std::string(camera_file), camera_param)) 
{return camera;}

看起来平平无奇只有两个子条件,其实蕴藏杀机,衍生出了14个分支,分别为:

  1. load_with_general_format == true
  2. load_with_general_format == false
  3. 函数loadCameraModelParametersWithSVFormat返回值为true
  4. 函数loadCameraModelParametersWithSVFormat返回值为false
  5. std::string(camera_file)中camera_file[char *]为空
  6. std::string(camera_file)中camera_file[char *]不为空
  7. 函数调用,不明
  8. 函数调用,不明

以及最后6个分支为函数loadCameraModelParametersWithSVFormat内部有三个if实现,即6个分支,共14个。

你可能感兴趣的:(C++开发,c++)