当前位置: 首页 > 知识库问答 >
问题:

c++ - lcov2.0分支覆盖率中关于std容器相关操作的分支未覆盖问题,如何解决?

红富
2023-11-10

我使用lcov2.0来检测分支覆盖率,但是会遇到很多和std容器相关的分支未覆盖的问题。

  • g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
  • gtest 1.12.x
  • lcov/genhtml: LCOV version 2.0-1

源码

// src/main.hpp#include <cstdint>#include <iostream>#include <map>#include <set>#include <stdexcept>using namespace std;class mytestint{public:    mytestint() = default;    mytestint(uint16_t id, uint16_t pr) : _id(id), _pr(pr) {}    uint16_t get_id() const    {        return _id;    }private:    uint16_t _id;    uint16_t _pr;};map<uint16_t, mytestint> _test_map;map<uint16_t, uint16_t> _test_map_pod;void test_emplace(uint16_t id, uint16_t pr){    // map with class    mytestint temp = {id, pr};    auto t = _test_map.emplace(id, temp);    auto k = _test_map.emplace(id, mytestint(id,pr));    auto s = _test_map.insert({pr, temp});    _test_map[id] = temp;    auto h = _test_map[pr];    // map with uint16_t    _test_map_pod.emplace(id,pr);    _test_map_pod.insert({pr,id});    _test_map_pod[id] = pr;}

gtest代码

#include "src/main.hpp"#include <gtest/gtest.h>TEST(MapTest, TestMap) {    EXPECT_NO_THROW(test_emplace(1,1));    EXPECT_NO_THROW(test_emplace(2,2));    EXPECT_NO_THROW(test_emplace(3,3));    EXPECT_NO_THROW(test_emplace(2,4));}int main(int argc, char **argv) {    ::testing::InitGoogleTest(&argc, argv);    return RUN_ALL_TESTS();}

lcov最终生成的报告长这样,所有insert和emplace相关的函数都会有一个未解决的分支

      92                 :           4 : void test_emplace(uint16_t id, uint16_t pr)      93                 :             : {      94                 :             :     // map with class      95                 :           4 :     mytestint temp = {id, pr};      96         [ +  - ]:           4 :     auto t = _test_map.emplace(id, temp);      97         [ +  - ]:           4 :     auto k = _test_map.emplace(id, mytestint(id,pr));      98         [ +  - ]:           4 :     auto s = _test_map.insert({pr, temp});      99         [ +  - ]:           4 :     _test_map[id] = temp;     100         [ +  - ]:           4 :     auto h = _test_map[pr];     101                 :             :     // map with uint16_t     102         [ +  - ]:           4 :     _test_map_pod.emplace(id,pr);     103         [ +  - ]:           4 :     _test_map_pod.insert({pr,id});     104         [ +  - ]:           4 :     _test_map_pod[id] = pr;     105                 :           4 : }

贴出我用的lcov命令

    g++ -std=c++17 test.cpp -o test -lgtest -lgtest_main -pthread -fprofile-arcs -ftest-coverage -fprofile-update=atomic && \    ./test && \    gcov -o . test.cpp && \    lcov --capture \         --rc branch_coverage=1 \         --directory . \         --output-file coverage_all.info \         --ignore-errors mismatch && \    lcov --remove coverage_all.info '*/usr/include/*' '*/usr/lib/*' '*/usr/lib64/*' \                                    '*/usr/local/include/*' '*/usr/local/lib/*'     \                                    '*/usr/local/lib64/*'     \        --rc branch_coverage=1 \        --output-file coverage.info \        --ignore-errors unused \        --ignore-errors mismatch && \    genhtml coverage.info \            --rc branch_coverage=1 \            --output-directory coverage_report 

我想知道要怎么覆盖上这些分支?因为现在要求分支覆盖率要达到某个百分比,但是代码里面有一大堆std库函数的操作而产生的分支,这些和自己实现的代码没有联系的分支很难被完全测试出来……

就想知道这里的分支未覆盖和这几个插入函数中的异常处理有关系吗?我看so上面一个远古帖子说在g++编译的时候屏蔽这些异常能解决一些分支。但是那样就完全没有办法使用try/catch等异常处理语句了,肯定不是个解决办法。

lcov用的人似乎太少了,国内和外网都没有找到一个很细致的分支覆盖率提高的教程(也有可能是我搜索的方式不对吧……很少上外网搜东西。)

关联问题 https://segmentfault.com/q/1010000044378276

共有1个答案

端木兴国
2023-11-10

这个问题涉及到代码覆盖率和异常处理的问题。要解决这个问题,你需要明白lcov工具是如何工作的,以及它为什么将这些std库函数的分支视为未覆盖。

首先,lcov工具在计算代码覆盖率时,它将每个源文件编译为二进制的覆盖信息文件(.gcda文件)。然后,它使用这些.gcda文件来生成一个总的覆盖信息文件(coverage_all.info),其中包含了源代码中的所有分支和路径的覆盖情况。

然而,lcov工具在生成总的覆盖信息文件时,它默认会忽略一些被认为是库函数或系统调用的代码块。这些代码块通常不包含在源文件中,而是包含在标准库或操作系统提供的二进制文件中。由于这些代码块不是由你编写的,因此lcov工具默认认为它们不需要被测试。

在你的情况下,问题出在std容器相关的插入和emplace操作上。这些操作是在标准库中定义的,因此它们被视为忽略的代码块,从而导致了这些分支被视为未覆盖。

要解决这个问题,你有几个选择:

  1. 增加异常处理:异常处理是C++的一个重要特性,因此在某些情况下,你可能需要使用try/catch语句来捕获和处理可能的异常。然而,这并不是一个理想的解决方案,因为它会使代码变得复杂且难以维护。
  2. 自定义覆盖率工具:你可以编写自己的工具或脚本,来记录std容器相关操作的覆盖情况。然后,你可以使用这些数据来生成一个自定义的覆盖信息文件,该文件将包含这些操作的覆盖情况。这种方法需要一些编程技能,但它可以让你更精确地控制代码的覆盖率。
  3. 使用其他覆盖率工具:除了lcov之外,还有许多其他的覆盖率工具可供选择,例如gcov、cppcheck等。这些工具可能更适合你的需求,特别是当你需要测试std容器相关操作时。
  4. 修改编译选项:你可以尝试修改编译选项来改变lcov的行为。例如,你可以尝试添加-fprofile-arcs-ftest-coverage选项来启用覆盖率检测。然而,这种方法可能会影响代码的性能和稳定性,因此在使用之前需要谨慎考虑。

总的来说,要解决这个问题需要一些工作量,但并不是不可能的。你可以根据你的具体需求和资源来选择最合适的解决方案。

 类似资料:
  • 我正在使用来衡量我的测试的代码覆盖率。我已经启用了分支机构覆盖,但我不能完全理解该报告。 没有分支保险,我得到100%的保险: 启用分支覆盖: 有问题的来源可以在这里找到。 <代码>21- 然而,<代码>53-

  • 主要内容:如何计算分支覆盖范围?分支覆盖技术用于覆盖控制流图的所有分支。它至少涵盖决策点的每个条件的所有可能结果(真和假)。分支覆盖技术是一种白盒测试技术,可确保每个决策点的每个分支都必须执行。 然而,分支覆盖技术和决策覆盖技术非常相似,但两者之间存在关键差异。决策覆盖技术涵盖每个决策点的所有分支,而分支测试涵盖代码的每个决策点的所有分支。 换句话说,分支覆盖遵循决策点和分支覆盖边缘。许多不同的指标可用于查找分支覆盖范围和决策覆

  • 我运行的插件生成html,xml和报告,以衡量我的测试测试的代码覆盖率。 我在本地以及在中成功地生成了这些报告,我的所有单元测试结果都反映在中,它向我展示了覆盖范围。 我的既有模块中覆盖范围的结果,也有依赖模块的结果。我已经验证了这使用为。 我没有得到声纳中相关模块的覆盖结果。任何人都知道我做错了什么。 我的插件是这样的 我的目标是

  • 我有一个交换系统,我用eclemma测试分支覆盖率。我们需要有至少80%的分支覆盖率,所以我正在尝试尽可能多的测试。然而,eclemma告诉我,这个交换机系统在分支覆盖方面没有经过充分测试。 我使用了简单的JUnit测试来测试每一个案例。仍然eclemma将其标记为黄色,并表示“19个分支中有7个错过了”。我会说只有7种方法可以通过这个交换系统(6个单独的案例都没有定义)。 我试着在堆栈溢出上搜索

  • 我正在致力于集成sonarqube在詹金斯管道。根据https://docs.sonarqube.org/pages/viewpage下面的文档,我已经用opencover使用sonar-csharp启用了sonarqube上的代码覆盖。action?pageid=6389770我还使用了分支插件。当我用/d:sonar.branch.name和/d:sonar.branch.target启动so

  • 问题内容: 我有一个Jenkins项目,对我的NodeJS项目进行SonarQube分析。我添加了对项目的依赖。在Jenkins构建配置中,首先运行一个shell脚本: 这将安装依赖项,运行测试并生成代码覆盖率报告,并生成cobertura-coverage.xml文件。 在shell脚本之后,我运行具有以下属性的代码覆盖: Jenkins作业通过SonarQube仪表板成功运行,该仪表板描述了项