惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Exploit Database - CXSecurity.com
J
Java Code Geeks
H
Help Net Security
B
Blog RSS Feed
G
Google Developers Blog
博客园 - 司徒正美
MongoDB | Blog
MongoDB | Blog
量子位
博客园 - 三生石上(FineUI控件)
The Cloudflare Blog
P
Proofpoint News Feed
小众软件
小众软件
人人都是产品经理
人人都是产品经理
云风的 BLOG
云风的 BLOG
V
V2EX
月光博客
月光博客
C
Check Point Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
A
Arctic Wolf
Help Net Security
Help Net Security
Schneier on Security
Schneier on Security
D
DataBreaches.Net
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Palo Alto Networks Blog
T
Tenable Blog
L
LangChain Blog
Attack and Defense Labs
Attack and Defense Labs
Google DeepMind News
Google DeepMind News
N
News and Events Feed by Topic
Forbes - Security
Forbes - Security
F
Fortinet All Blogs
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
大猫的无限游戏
大猫的无限游戏
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Y
Y Combinator Blog
WordPress大学
WordPress大学
Stack Overflow Blog
Stack Overflow Blog
V
Visual Studio Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
NISL@THU
NISL@THU
GbyAI
GbyAI
博客园 - Franky
S
Secure Thoughts
有赞技术团队
有赞技术团队
PCI Perspectives
PCI Perspectives
U
Unit 42

轶哥博客

blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog blog
blog
2023-05-25 · via 轶哥博客

测试覆盖率是衡量软件测试质量的一个重要指标,它表示在运行测试用例时,被执行到的代码占总代码数的百分比。通过测试覆盖率,我们可以评估测试集对源码的覆盖程度及潜在漏洞。

本文将介绍两种使用LLVM实现C++测试覆盖率的方法:

  • 方案1 使用lcov和llvm-cov将gcda文件转换为lcov.info文件。
  • 方案2 使用grcov。

方案1:使用lcov和llvm-cov实现gcda -> gcov -> lcov.info

1. 环境准备

首先,确保已安装LLVM、Clang、lcov以及其相关工具。

各平台安装方法参考https://github.com/yi-ge/cpp-practice

其中Windows平台安装lcov:

choco install lcov

然后执行lcov命令的时候需要手动使用perf执行安装目录下bin/lcov程序。

也可以在WSL2或者其他可以执行Shell脚本的类 Unix 终端(例如Git Bash、Cygwin等)安装lcov

2. 编译代码与生成.gcda文件

在这里,我们提供两种方法来生成.gcda文件:

方法一:

使用以下命令启用覆盖率信息收集,并编译你的C++项目:

clang++ -fprofile-instr-generate -fcoverage-mapping -o your_program your_source.cpp

其中-fprofile-instr-generate-fcoverage-mapping选项用于激活覆盖率信息收集。

方法二:

在CMakeLists.txt文件中添加coverage相关参数(LLVM 8+),例如:

set(CMAKE_CXX_FLAGS
    "${CMAKE_CXX_FLAGS} -fno-inline -O0 -fprofile-arcs -ftest-coverage")

接下来按照普通流程编译和运行项目即可生成对应的.gcda文件。

3. 执行程序

接下来,运行编译好的可执行文件:

./your_program

运行完毕后,会在当前目录下生成.profraw文件(方法一),或 .gcda 文件(方法二)。该文件记录了覆盖率原始数据。

4. 转换.profraw文件为.gcda文件(仅方法一)

如果使用方法一,请使用llvm-profdata工具将.profraw文件转换为.gcda格式:

llvm-profdata merge -sparse default.profraw -o your_program.gcda

5. 使用llvm-cov生成.gcov文件

通过llvm-cov gcov命令将.gcda文件转换为.gcov文件:

llvm-cov gcov -f -b your_source.gcda

6. 使用lcov生成lcov.info文件

现在我们已经得到了.gcov文件,接下来可以用lcov合并覆盖率数据并生成lcov.info文件:

lcov --capture --directory . --output-file lcov.info

由于在基于llvm的项目中依次执行llvm-cov gcov很麻烦,除了递归脚本外,还推荐另外一种方法,具体实现方案如下:

llvm-gcov.sh文件:

#!/bin/bash
uNames=$(uname -s)
osName=${uNames:0:4}

if [ "$osName" == "Darw" ]; then # Darwin
  exec llvm-cov gcov "$@"
elif [ "$osName" == "Linu" ]; then # Linux
  exec llvm-cov-16 gcov "$@"
elif [ "$osName" == "MING" ]; then # MINGW, windows, git-bash
  exec llvm-cov-16 gcov "$@"
fi

llvm-gcov.bat文件:

@echo off

:DetectOS
if "%OS%" == "Windows_NT" (
  set "osName=Win"
) else (
  echo Unsupported platform: %OS%
  exit /b 1
)

:RunLLVMCov
if "%osName%" == "Win" (
  llvm-cov gcov %*
) else (
  echo Unsupported platform: %osName%
  exit /b 1
)

创建名为scripts的文件夹,并将提供的llvm-gcov.sh (macOS, Linux)或llvm-gcov.bat (Windows) 文件放入其中。这些脚本用于在不同平台上调用正确的llvm-cov工具。

参考以下bash脚本生成覆盖率测试文件lcov.info:

#!/bin/bash
# 使用bash shell执行此脚本

COVERAGE_FOLDER=coverage
COVERAGE_FILE=lcov.info
REPORT_FOLDER=report

# 删除已存在的覆盖率文件夹,然后创建一个新的覆盖率文件夹
rm -rf ${COVERAGE_FOLDER}
mkdir ${COVERAGE_FOLDER}

# 获取操作系统名称并截取前四个字符
uNames=$(uname -s)
osName=${uNames:0:4}

# 删除与当前单元测试无关的.gcda文件
# find build -name "*.gcda" -not -path "*flip_columns_for_maximum_number_of_equal_rows*" -exec rm {} \;

# 设置临时覆盖率文件路径
TMP_COVERAGE_FILE=${COVERAGE_FOLDER}/${COVERAGE_FILE}_tmp

# 根据操作系统类型执行相应的lcov命令
if [ "$osName" == "Darw" ]; then # Darwin
  echo "Mac"
  lcov --gcov-tool $PWD/scripts/llvm-gcov.sh --rc lcov_branch_coverage=1 -c -d build -o ${TMP_COVERAGE_FILE}
elif [ "$osName" == "Linu" ]; then # Linux
  echo "Linux"
  lcov --gcov-tool $PWD/scripts/llvm-gcov.sh --rc lcov_branch_coverage=1 -c -d build -o ${TMP_COVERAGE_FILE}
elif [ "$osName" == "MING" ]; then # MINGW, windows, git-bash
  echo "Windows"
  lcov --gcov-tool $PWD/scripts/llvm-gcov.sh --rc lcov_branch_coverage=1 -c -d build -o ${TMP_COVERAGE_FILE}
fi

# 从临时覆盖率文件中移除包含目录
echo "从临时覆盖率文件中移除包含目录"
lcov --remove ${TMP_COVERAGE_FILE} -o ${TMP_COVERAGE_FILE} "*/include/*"

# 从临时覆盖率文件中提取src目录下的覆盖率数据,并保存到最终的覆盖率文件
lcov --rc lcov_branch_coverage=1 -e ${TMP_COVERAGE_FILE} "*src*" -o ${COVERAGE_FOLDER}/${COVERAGE_FILE}

# 生成覆盖率报告(注释掉,如需启用,请取消注释)
# genhtml --rc genhtml_branch_coverage=1 ${COVERAGE_FOLDER}/${COVERAGE_FILE} -o ${COVERAGE_FOLDER}/${REPORT_FOLDER}

在当前目录下执行此脚本,生成覆盖率测试文件lcov.info

7. 生成可视化报告

使用genhtml命令将lcov.info转换为HTML格式:

genhtml -o coverage_report --branch-coverage lcov.info

这将在coverage_report目录下生成一个包含覆盖率详细信息的HTML报告。通过浏览器打开index.html来查看报告。

方案2:使用grcov实现C++测试覆盖率

grcov是一个用Rust编写的覆盖率收集工具,可以直接分析.gcda文件并生成覆盖率报告。

首先安装grcov。

如果已经配置好Rust环境以及对应的cargo工具:

cargo install grcov

否则可以直接从github仓库下载编译好的二进制文件,可以参考跨平台自动下载及安装脚本https://github.com/yi-ge/cpp-practice/blob/main/scripts/grcovDownloader.cpp

然后使用以下命令运行测试并生成覆盖率报告:

LLVM_PROFILE_FILE="your_program-%p-%m.profraw" ./your_program
grcov . --binary-path ./ --source-dir . --output-path cover/lcov.info --output-type lcov

这将生成一个名为lcov.info的文件,其中包含覆盖率数据。同样,你可以使用直接生成HTML可视化报告:

grcov . --binary-path ./ --source-dir . --output-path coverage/ --output-type html

总结

如上所述,在方案1中我们可以使用lcov和llvm-cov工具链生成覆盖率报告,或者通过添加coverage flags在CMakeLists.txt中直接生成.gcda文件。在方案2中,我们可以使用grcov直接分析.gcda文件并生成覆盖率报告。这两种方法都可以满足不同的需求,方案1更适用于熟悉lcov工具链的开发者,而方案2对于喜欢尝试新工具的开发者来说是一个很好的选择。

无论采用哪种方案,测试覆盖率是提高软件质量、降低潜在风险的关键指标,因此建议在项目开发过程中充分利用这些工具和方法,确保代码的健壮性和可靠性。

另外,grcov的优点是跨平台更方便。尤其是对于Windows平台,在不考虑wsl或者类Unix终端的情况下,安装perf来直接运行lcov程序非常容易出现问题。因此,更推荐使用方案2。