C++单元测试覆盖率统计工具:GCOV+LCOV

1. gcov基础

1.1 gcov概述

gcov是GNU编译器集合(GCC)的一个测试覆盖分析工具,它能够测量程序的执行覆盖率。gcov可以分析源代码中哪些行被执行过,哪些分支被采取过,以及哪些函数被调用过。这对于软件开发者来说是一个宝贵的资源,因为它有助于识别未被测试覆盖的区域,从而提高代码质量和减少潜在的bug。

1.2 安装gcov

gcov通常与GCC捆绑在一起,因此如果你的系统中已经安装了GCC,那么很可能已经拥有了gcov。以下是在不同操作系统上安装gcov的指南:

  • Linux: 大多数Linux发行版可以通过包管理器安装GCC,如下所示:
    sudo apt-get install gcc
    
  • macOS: 对于macOS用户,可以使用Homebrew来安装GCC:
    brew install gcc
    
  • Windows: Windows用户可以通过安装MinGW或Cygwin来获取gcov。

安装完成后,可以通过运行gcov --version来验证gcov是否已经正确安装。

1.3 基本使用方法

使用gcov的第一步是确保你的程序是为测试覆盖率编译的。这通常意味着在编译时需要添加特定的GCC选项。以下是使用gcov的步骤:

  1. 编译源代码: 使用-fprofile-arcs-ftest-coverage选项编译你的源代码。例如,如果你有一个名为example.c的源文件,你可以使用以下命令来编译它:
    gcc -fprofile-arcs -ftest-coverage -o example example.c
    
  2. 运行程序: 运行编译后的程序,这将生成.gcda文件,记录程序的执行信息。
  3. 生成覆盖率报告: 使用gcov命令来分析这些数据并生成覆盖率报告:
    ./example
    gcov example.c
    

这将生成一个example.gcov文件,其中包含了详细的覆盖率信息。

1.4 gcov的输出

gcov的输出文件.gcov提供了丰富的信息,包括:

  • 覆盖率摘要:显示总体的行覆盖率、分支覆盖率和函数覆盖率。
  • 详细覆盖率数据:为每个源文件中的每行代码提供执行次数,未执行的代码将以红色显示(在支持颜色的编辑器或IDE中)。
  • 函数和分支的覆盖率:显示每个函数的执行次数和覆盖率,以及每个分支的执行情况。

1.4.1 示例

假设我们有以下简单的C语言程序example.c

#include <stdio.h>int main() {int a = 5;if (a > 3) {printf("a is greater than 3\n");}return 0;
}

按照上述步骤编译并运行程序后,gcov的输出可能如下所示:

File 'example.c'
Lines executed:100.00% of 4
Branches executed:100.00% of 1
Taken at least once:1
No branches
Functions executed:100.00% of 1

这个输出告诉我们,所有的4行代码都被执行了,包括一个条件分支,且所有的函数都被调用了。

1.4.2 使用gcov的技巧

  • 排除文件:使用--exclude选项来排除不需要分析的文件。
  • 汇总报告:使用-all-blocks来生成所有分支的覆盖率报告。
  • 过滤未覆盖的代码:使用--branch-probabilities来显示分支的执行概率,帮助识别未覆盖的分支。

2. lcov基础

2.1 lcov概述

lcov是一个功能强大的工具,用于收集和分析由gcov生成的代码覆盖率数据。与gcov相比,lcov提供了更为丰富的功能,包括生成易于阅读和导航的HTML格式的覆盖率报告。lcov不仅能够提供代码覆盖率的详细视图,还能帮助开发者通过图形界面快速定位未覆盖的代码区域。

2.2 安装lcov

lcov通常与GCC一起提供,但如果你的环境中没有lcov,可以通过以下方式安装:

  • Linux: 在大多数Linux发行版中,可以通过包管理器安装lcov:
    sudo apt-get install lcov
    
  • macOS: 使用Homebrew安装lcov:
    brew install lcov
    
  • Windows: Windows用户可以通过安装Linux子系统或使用Cygwin来获取lcov。

安装完成后,可以通过运行lcov --version来验证lcov是否已经正确安装。

2.3 基本使用方法

lcov的使用相对简单,它可以通过命令行与gcov配合工作。以下是使用lcov的基本步骤:

  1. 编译源代码: 首先,需要使用gcov支持的编译选项编译源代码,如前所述。
  2. 运行程序: 运行编译后的程序以生成.gcda文件。
  3. 收集覆盖率数据: 使用lcov命令收集覆盖率数据:
    lcov --capture --directory . --output-file coverage.info
    
  4. 生成HTML报告: 将收集到的数据转换为HTML格式的报告:
    genhtml coverage.info --output-directory coverage_report
    

这将生成一个名为coverage_report的目录,其中包含了详细的HTML覆盖率报告。

2.4 lcov的输出

lcov生成的HTML报告提供了丰富的可视化信息,包括:

  • 目录树:显示项目的目录结构,可以快速导航到不同的源文件。
  • 文件覆盖率:每个文件的覆盖率摘要,包括行覆盖率、分支覆盖率和函数覆盖率。
  • 行覆盖率详情:每个文件中每行代码的覆盖情况,未覆盖的行将以不同颜色高亮显示。
  • 分支覆盖率详情:显示每个分支的覆盖情况,包括分支的执行次数和覆盖率。

2.4.1 示例

假设我们继续使用前一章中的example.c程序,以下是使用lcov生成HTML报告的示例:

  1. 编译源代码:
    gcc -fprofile-arcs -ftest-coverage -o example example.c
    
  2. 运行程序:
    ./example
    
  3. 收集覆盖率数据:
    lcov --capture --directory . --output-file coverage.info
    
  4. 生成HTML报告:
    genhtml coverage.info --output-directory coverage_report
    

生成的HTML报告可以在coverage_report目录中查看。报告将包含一个index.html文件,这是报告的主页面,提供了项目的覆盖率摘要和目录树。点击example.c链接,将打开一个详细页面,显示该文件的覆盖率详情。

2.4.2 使用lcov的技巧

  • 排除特定文件:使用--exclude选项来排除特定文件或目录,例如:
    lcov --capture --directory . --output-file coverage.info --exclude "/usr/*"
    
  • 过滤未覆盖的代码:使用--remove选项来过滤掉未覆盖的代码段。
  • 自定义报告:使用genhtml的选项来自定义HTML报告的外观和行为,例如设置标题、添加徽章等。

3. 结合gcov和lcov

3.1 整合gcov和lcov

gcov和lcov是两个互补的工具,它们可以一起工作来提供更全面的代码覆盖率分析。gcov负责生成覆盖率数据,而lcov则用于收集这些数据并生成易于理解的HTML报告。这种整合不仅提高了分析的效率,还使得结果更加直观。

3.1.1 整合步骤

以下是整合gcov和lcov的基本步骤:

  1. 编译源代码: 使用gcov支持的编译选项编译源代码。
    gcc -fprofile-arcs -ftest-coverage -o my_program my_program.c
    
  2. 运行程序: 执行编译后的程序以生成.gcda.gcno文件。
    ./my_program
    
  3. 收集覆盖率数据: 使用lcov收集覆盖率数据。
    lcov --capture --directory . --output-file coverage.info
    
  4. 生成HTML报告: 使用lcov的genhtml工具生成HTML格式的报告。
    genhtml coverage.info --output-directory coverage_report
    

3.2 高级配置

3.2.1 配置文件

lcov可以使用配置文件(.lcovrc)来定义高级选项,如排除特定目录或文件。例如,创建一个.lcovrc文件并添加以下内容来排除测试目录:

# .lcovrc
# Exclude test directory
exclude_test_dir='*tests*'

然后在运行lcov时指定配置文件:

lcov --rc lcovrc_file=.lcovrc --capture --directory . --output-file coverage.info

3.2.2 排除特定文件或函数

使用lcov的--exclude选项来排除特定文件或函数的覆盖率统计。例如,排除所有.h文件:

lcov --capture --directory . --exclude "*.h" --output-file coverage.info

3.2.3 设置阈值

可以设置覆盖率的阈值,以确保代码质量。例如,设置最低行覆盖率为80%:

genhtml coverage.info --branch-coverage --functions-coverage --legend --title "Code Coverage" --output-directory coverage_report --threshold-percentage 80

3.3 自动化集成

3.3.1 CI/CD集成

将gcov和lcov集成到持续集成/持续部署(CI/CD)流程中,可以自动化测试覆盖率的收集和报告生成。大多数现代CI/CD平台(如Jenkins, Travis CI, GitHub Actions等)都支持自定义脚本,可以添加以下步骤:

  1. 编译源代码: 在构建脚本中添加编译命令。
  2. 运行测试: 执行测试用例。
  3. 收集覆盖率数据: 使用lcov收集数据。
  4. 生成报告: 使用genhtml生成HTML报告。
  5. 上传报告: 将生成的报告上传到服务器或存储库。

3.3.2 示例

假设我们使用GitHub Actions进行CI/CD,以下是.github/workflows目录下的一个示例.yml文件:

name: Code Coverageon: [push, pull_request]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v2- name: Set up GCCrun: sudo apt-get install gcc- name: Compile with Coveragerun: gcc -fprofile-arcs -ftest-coverage -o my_program my_program.c- name: Run Programrun: ./my_program- name: Collect Coverage Datarun: lcov --capture --directory . --output-file coverage.info- name: Generate HTML Reportrun: genhtml coverage.info --output-directory coverage_report- name: Upload Coverage Reportuses: actions/upload-artifact@v2with:name: Code Coverage Reportpath: coverage_report

这个工作流会在每次提交或拉取请求时自动运行,编译源代码,运行程序,收集覆盖率数据,生成HTML报告,并上传报告作为工件。

3.4 可视化覆盖率

3.4.1 覆盖率徽章

可以使用服务如Codecov或Coveralls来显示覆盖率徽章在你的README文件或Pull Request中。这些服务可以解析你的覆盖率报告,并提供一个可视化的徽章来展示当前的覆盖率状态。

4. 场景问题及解决方案

4.1 场景一:覆盖率报告中发现未覆盖的代码

问题描述:在生成的覆盖率报告中,发现某些函数或代码块未被测试覆盖。

解决方案

  1. 分析覆盖率报告:查看lcov生成的HTML报告,定位未覆盖的代码区域。
  2. 审查代码逻辑:检查未覆盖的代码是否为正常逻辑,还是潜在的代码异味或错误。
  3. 编写测试用例:为未覆盖的代码编写新的测试用例或更新现有测试用例。
  4. 更新测试脚本:在测试脚本中添加新的测试用例,并确保它们能够触发未覆盖的代码路径。

示例脚本

# 假设我们发现函数 `calculate_tax` 未被覆盖# 步骤1:在测试文件 test_my_program.c 中添加测试用例
// test_my_program.c
void test_calculate_tax() {// 测试不同的输入情况assert(calculate_tax(100) == 10); // 假设税率为10%assert(calculate_tax(200) == 20);// 添加更多测试用例以覆盖所有分支
}// 步骤2:编译测试程序
gcc -fprofile-arcs -ftest-coverage -o test_my_program test_my_program.c my_program.c// 步骤3:运行测试程序
./test_my_program// 步骤4:再次收集覆盖率数据
lcov --capture --directory . --output-file coverage.info// 步骤5:生成新的HTML报告
genhtml coverage.info --output-directory coverage_report// 步骤6:检查新的覆盖率报告是否覆盖了之前未覆盖的代码

4.2 场景二:覆盖率报告过大,难以管理

问题描述:项目中源文件众多,生成的覆盖率报告文件过大,难以有效管理和分析。

解决方案

  1. 使用lcov的排除功能:通过.lcovrc配置文件排除不必要的目录或文件。
  2. 模块化覆盖率报告:为不同的模块生成单独的覆盖率报告。
  3. 使用CI工具的报告聚合功能:如果使用CI工具,可以利用其报告聚合功能来管理多个覆盖率报告。

示例脚本

# 步骤1:创建.lcovrc配置文件,排除测试目录和第三方库
echo "exclude_test_dir='*tests*'" > .lcovrc
echo "exclude_directories='*/third_party/*'" >> .lcovrc# 步骤2:为每个模块单独收集覆盖率数据
lcov --capture --directory ./module1 --output-file coverage_module1.info
lcov --capture --directory ./module2 --output-file coverage_module2.info
# 重复此步骤为其他模块生成覆盖率数据# 步骤3:为每个模块生成HTML报告
genhtml coverage_module1.info --output-directory coverage_report_module1
genhtml coverage_module2.info --output-directory coverage_report_module2
# 重复此步骤为其他模块生成HTML报告# 步骤4:在CI工具中配置报告聚合(以Jenkins为例)
# 在Jenkins中配置Post-build Action以聚合所有模块的覆盖率报告

4.3 场景三:CI/CD流程中的覆盖率下降

问题描述:在CI/CD流程中,新提交的代码导致整体覆盖率下降。

解决方案

  1. 立即通知:配置CI/CD流程,当覆盖率下降时发送通知给相关开发者。
  2. 分析覆盖率变化:确定覆盖率下降的原因,是否是因为新代码未被覆盖,或者是因为原有测试用例被破坏。
  3. 修复问题:根据分析结果,编写新的测试用例或修复现有测试用例。
  4. 重新运行测试:在修复问题后,重新运行测试并验证覆盖率。

示例脚本(GitHub Actions):

name: Code Coverage Checkon: [push, pull_request]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v2- name: Set up GCCrun: sudo apt-get install gcc- name: Compile with Coveragerun: gcc -fprofile-arcs -ftest-coverage -o my_program my_program.c- name: Run Programrun: ./my_program- name: Collect Coverage Datarun: lcov --capture --directory . --output-file coverage.info- name: Check Coverage Raterun: |current_coverage=$(genhtml -e coverage.info)base_coverage=$(grep -oP 'Overall coverage' base_coverage.info | grep -oP '\d+')if [ "$current_coverage" -lt "$base_coverage" ]; thenecho "Coverage rate has decreased!"exit 1fi- name: Generate HTML Reportrun: genhtml coverage.info --output-directory coverage_report- name: Upload Coverage Reportuses: actions/upload-artifact@v2with:name: Code Coverage Reportpath: coverage_report

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/18453.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring AOP原理详解:动态代理与实际应用

1. Spring AOP概述 1.1 什么是AOP AOP&#xff08;Aspect-Oriented Programming&#xff0c;面向切面编程&#xff09;是一种编程范式&#xff0c;旨在将横切关注点&#xff08;Cross-Cutting Concerns&#xff09;从业务逻辑中分离出来。横切关注点是指那些分散在应用程序多…

Android基础-Service的介绍

在Android系统中&#xff0c;Service是一个重要的后台组件&#xff0c;用于执行长时间运行的操作&#xff0c;而不需要提供用户界面。以下是对Service的功能、作用以及生命周期的详细介绍。 Service的功能和作用 后台执行&#xff1a; Service允许应用程序在后台执行操作&…

【数据结构】AVL树——平衡二叉搜索树

个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 祝福语&#xff1a;愿你拥抱自由的风 目录 二叉搜索树 AVL树概述 平衡因子 旋转情况分类 左单旋 右单旋 左右双旋 右左双旋 AVL树节点设计 AVL树设计 详解单旋 左单旋 右单旋 详解双旋 左右双旋 平衡因子情况如…

阿里开源React应用动效解决方案:ant-motion

ant-motion&#xff1a;简化动效开发&#xff0c;提升用户体验 - 精选真开源&#xff0c;释放新价值。 概览 Ant Motion是由Ant Design团队精心打造&#xff0c;专为React应用设计的动画规范和组件库。它不仅仅是一套动画规范&#xff0c;更是一个完整的解决方案&#xff0c;旨…

C# yolov8 TensorRT Demo

C# yolov8 TensorRT Demo 目录 效果 说明 项目 代码 下载 效果 说明 环境 NVIDIA GeForce RTX 4060 Laptop GPU cuda12.1cudnn 8.8.1TensorRT-8.6.1.6 版本和我不一致的需要重新编译TensorRtExtern.dll&#xff0c;TensorRtExtern源码地址&#xff1a;https://githu…

2024年JAVA、C++、Pyhton学哪种语言更容易进国央企?

对于不同编程语言在进入国有企业的观点大体是正确的&#xff0c;不过在实际选择时还需考虑一些因素。我这里有一套编程入门教程&#xff0c;不仅包含了详细的视频讲解&#xff0c;项目实战。如果你渴望学习编程&#xff0c;不妨点个关注&#xff0c;给个评论222&#xff0c;私信…

【CSDN独家公开】Python解析.SchDoc格式文件转换为json文件

前情提要 因工作需求&#xff0c;需要解析.SchDoc格式文件&#xff0c;提取文本和位置关系&#xff0c;通常方式是转换为图片或PDF&#xff0c;再进行OCR&#xff0c;但是这样识别精度太低了 Github找了好些项目&#xff0c;都不支持 PyAltium不支持 https://github.com/plu…

apexcharts数据可视化之饼图

apexcharts数据可视化之饼图 有完整配套的Python后端代码。 本教程主要会介绍如下图形绘制方式&#xff1a; 基础饼图单色饼图图片饼图 基础饼图 import ApexChart from react-apexcharts;export function SimplePie() {// 数据序列const series [44, 55, 13, 43, 22]// …

AI大模型:掌握未知,开启未来

AI大模型的工作原理 AI大模型是指通过大量数据和复杂算法训练出的能够理解和生成自然语言文本的人工智能模型。它们背后的核心技术主要包括深度学习、神经网络和自然语言处理。以下是详细的工作原理以及通俗易懂的类比&#xff1a; 1. 数据收集和预处理 AI大模型的训练首先需…

【面试】什么是Java堆内存溢出?

目录 1. 概念2. 堆内存溢出的原因2.1 内存泄露2.2 堆内存设置过小2.3 大量对象创建2.4 静态集合类2.5 外部资源没有及时释放 3. 避免内存溢出的建议 1. 概念 1.Java堆内存溢出&#xff08;Java Heap Memory Overflow&#xff09;。2.是指Java虚拟机&#xff08;JVM&#xff09…

java —— 常用类

一、System 类 System 类内部的构造方法是 private 修饰的&#xff0c;所以不能实例化&#xff0c;普通方法均为静态方法。 &#xff08;一&#xff09;.currentTimeMillis() 括号内无参数&#xff0c;返回值为距离1970年1月1日0时0分0秒之间的毫秒数。 long timeSystem.cu…

全面解析开源RTSP流媒体服务器:功能、性能与应用场景对比

本文综合分析了多个开源RTSP流媒体服务器&#xff0c;包括EasyDarwin、RtspServer、SRS等&#xff0c;深入探讨它们的功能特性、技术实现、性能对比及应用场景&#xff0c;旨在为开发者提供全面的选型参考。 文章目录 开源RTSP流媒体服务器概述RTSP协议简介开源RTSP服务器的重要…

【JavaScript】P5 数组与常量

目录 1 数组1.1 数组的声明1.2 数组的基本术语 2 常量 1 数组 如果将多个数据存储在单一个变量名下 -> 数组。 数组&#xff08;array&#xff09;&#xff0c;可以将一组数据存储在单个变量名下。 1.1 数组的声明 let 数组名 [数据1, 数据2, ..., 数据n]数组是有序的&a…

APM2.8内置罗盘校准

如果你有外置罗盘&#xff0c;可以不用校准内置罗盘&#xff0c;可以忽略此文。推荐使用外置罗盘&#xff0c;内置罗盘容易受干扰。 使用内置罗盘需要插入飞控GPS接口旁边的跳线帽。如图&#xff1a; 如果要使用内置罗盘&#xff0c;而又加了GPS的&#xff0c;记得一定要把GPS…

深入探索Qt框架系列之元对象编译器

上一篇文章简单介绍了Qt框架中的三大编译器&#xff08;MOC、UIC、RCC&#xff09;&#xff0c;其中我认为最核心&#xff0c;最重要的就是元对象编译器&#xff08;MOC&#xff09;&#xff0c;下面我们将深入探索MOC生成的代码&#xff0c;并逐步解析。 本文将以下面的源码来…

【错误记录】HarmonyOS 运行报错 ( Failure INSTALL _PARSE _FAILED _USESDK _ERROR )

文章目录 一、报错信息二、问题分析三、解决方案 一、报错信息 在 DevEco Studio 中 , 使用 远程设备 , 向 P40 Failure[INSTALL_PARSE_FAILED_USESDK_ERROR] compileSdkVersion and releaseType of the app do not match the apiVersion and releaseType on the device. 二、…

SpringMVC枚举类型字段处理

在日常的项目开发中经常会遇到一些取值范围固定的字段&#xff0c;例如性别、证件类型、会员等级等&#xff0c;此时我们可以利用枚举来最大程度减少字段的乱定义&#xff0c;统一管理枚举的值。 SpringMVC中对于枚举也有默认的处理策略&#xff1a; 对于RequestParam&#xf…

管理开发进度

在系统开发现场&#xff0c;必须要对项目的推进状况进行管理。不过&#xff0c;针对大型项目&#xff0c;要一下子对其整体进行统一的管理是很困难的。这时就需要将其划分成更小的单位进行管理。 这种用于分解的单位被称为任务。以任务为单位对开发进度进行管理的方法…

平常心看待已发生的事

本篇主要记录自己在阅读此篇文章&#xff08;文章链接&#xff1a; 这才是扼杀员工积极性的真正原因&#xff08;管理者必读&#xff09; &#xff09;和这两天京东的东哥“凡是长期业绩不好&#xff0c;从来不拼搏的人&#xff0c;不是我的兄弟”观点后的一些想法。 自己在微…

静态测试---基于WorkList的活跃变量分析

本文主要用于记录在活跃变量分析实验中的报错及解决&#xff0c;涉及静态测试的详细原理内容较少&#xff0c;编译运行底层逻辑偏多。 一、实验要求 1&#xff09;使用llvm基于框架实现一个基于WorkList的活跃变量分析demo。变量在某个程序点有两种状态&#xff0c;live 或 dea…