6 C++与Jenkins和SonarQube
6.1单元测试Googletest及在Jenkins中的应用
GoogleTest 是 Google 开发的一个跨平台的 C++ 测试框架,用于编写和运行单元测试。它是目前 C++ 生态中最流行的测试框架之一,广泛应用于工业界和开源项目中。
6.1.1 核心特性
1)主要功能
✔丰富的断言机制- 提供多种断言宏用于测试验证
✔测试发现机制- 自动注册测试用例,无需手动维护测试列表
✔测试固件(Test Fixtures)- 支持测试环境的设置和清理
✔参数化测试- 支持使用不同参数运行同一测试逻辑
✔死亡测试- 专门测试程序崩溃或断言失败的情况
✔与构建系统集成- 支持CMake、Bazel等主流构建系统
2)断言类型
6.1.2. 基本用法
1 简单测试用例
cpp
#include <gtest/gtest.h>
TEST(TestSuiteName, TestName) {
EXPECT_EQ(2+2, 4);
ASSERT_NE(5, 3) << "额外的失败信息";
}
2 测试固件(Fixture)
cpp
class MyFixture : public ::testing::Test {
protected:
void SetUp() override {
// 测试前初始化
data = new int(42);
}
void TearDown() override {
// 测试后清理
delete data;
}
int* data;
};
TEST_F(MyFixture, Test1) {
ASSERT_NE(data, nullptr);
EXPECT_EQ(*data, 42);
}
3 参数化测试
bash
# 使用vcpkg
vcpkg install gtest
# 使用apt (Ubuntu)
sudo apt install libgtest-dev
# 使用源码编译
git clone https://github.com/google/googletest.git
cd googletest
mkdir build && cd build
cmake .. && make && sudo make install
6.1.3. 安装与集成
1)安装方法
bash
# 使用vcpkg
vcpkg install gtest
# 使用apt (Ubuntu)
sudo apt install libgtest-dev
# 使用源码编译
git clone https://github.com/google/googletest.git
cd googletest
mkdir build && cd build
cmake .. && make && sudo make install
2)CMake集成示例
cmake
find_package(GTest REQUIRED)
add_executable(MyTests test1.cpp test2.cpp)
target_link_libraries(MyTests GTest::GTest GTest::Main)
6.1.4. 高级特性
1 死亡测试
cpp
TEST(DeathTest, InvalidPointer) {
int* p = nullptr;
EXPECT_DEATH(*p = 42, ".*Segmentation fault.*");
}
2)类型参数化测试
cpp
template <typename T>
class TypedTest : public ::testing::Test {
};
TYPED_TEST_SUITE_P(TypedTest);
TYPED_TEST_P(TypedTest, SizeTest) {
EXPECT_GT(sizeof(TypeParam), 0);
}
REGISTER_TYPED_TEST_SUITE_P(TypedTest, SizeTest);
using MyTypes = ::testing::Types<char, int, double>;
INSTANTIATE_TYPED_TEST_SUITE_P(MyPrefix, TypedTest, MyTypes);
3)测试事件监听
cpp
class MyListener : public ::testing::EmptyTestEventListener {
void OnTestStart(const ::testing::TestInfo& test_info) override {
std::cout << "Starting test: " << test_info.name() << std::endl;
}
};
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
::testing::UnitTest::GetInstance()->listeners().Append(new MyListener);
return RUN_ALL_TESTS();
}
6.1.5. 最佳实践
1)测试命名规范:使用TestSuiteName_TestName_Test风格
2)优先使用EXPECT而非ASSERT,除非后续测试依赖前置条件
3)保持测试独立:测试之间不应有依赖关系
4)测试代码质量:测试代码应与产品代码保持相同质量标准
5)结合覆盖率工具:如gcov/lcov确保测试充分性
6.1.6. 与其他工具对比
6.1.7. 典型应用场景
✅ 单元测试驱动开发(TDD)
✅ 回归测试保障
✅ API接口测试
✅ 算法正确性验证
✅ 跨平台兼容性测试
6.1.8 与Jenkins集成
stages{
stage('gtest'){
steps {
echo "开始编译gtest"
sh '''
cd /home/jerry/googletest-main/googletest/myworkspace/process/nomal/ \
&&g++ ../../src/TestAll.cpp process.h process.cpp processTest.cpp ../../src/CallArgs.h ../../src/CallArgs.cpp -o process -lgtest -lgmock -lpthread -std=c++14 -fprofile-arcs -ftest-coverage \
&&./process --gtest_output="xml:output.xml"\
&&xsltproc ./gtest2html/gtest2html.xslt ./output.xml >./out/out.html
'''
echo "结束编译gtest"
}
}
…
post{
always{
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'/home/jerry/googletest-main/googletest/myworkspace/process/nomal/out/',
reportFiles:'out.html',
reportName:'My Test Reports',
reportTitles:'The Test Report'])
}
6.2 Gcov介绍及在Jenkins中的应用
Gcov(GNU Coverage)是GCC(GNU Compiler Collection)自带的一个代码覆盖率分析工具,用于统计程序中哪些代码被执行过,哪些没有被执行。它常用于单元测试、软件测试优化和代码质量分析,帮助开发者发现未测试的代码路径。
6.2.1. Gcov 的主要功能
·语句覆盖率(Statement Coverage):统计每行代码是否被执行。
·分支覆盖率(Branch Coverage):检查if-else、switch-case等分支是否被覆盖。
·函数覆盖率(Function Coverage):统计哪些函数被调用过。
·输出详细的覆盖率报告(.gcov 文件),便于分析。
6.2.2. Gcov 的基本使用流程
1)编译代码时启用Gcov
使用-fprofile-arcs -ftest-coverage编译选项(GCC):
bash
gcc -fprofile-arcs -ftest-coverage -o my_program my_program.c
·-fprofile-arcs:记录代码执行路径。
·-ftest-coverage:生成 .gcno 文件(用于后续分析)。
2)运行程序,生成.gcda文件
bash
./my_program
运行后,会生成.gcda文件(记录实际执行情况)。
3)使用Gcov生成覆盖率报告
bash
gcov my_program.c
·生成my_program.c.gcov文件,显示每行代码的执行次数。
·示例输出:
text
-: 10: printf("Hello, World!\n");
1: 11: return 0;
o-表示未执行,1表示执行了1次。
6.2.3. Gcov 输出示例
1)原始 Gcov 报告
text
-: 0:Source:my_program.c
-: 0:Graph:my_program.gcno
-: 0:Data:my_program.gcda
-: 0:Runs:1
-: 0:Programs:1
1: 1:#include <stdio.h>
1: 2:
1: 3:int main() {
1: 4: printf("Hello, Gcov!\n");
1: 5: return 0;
-: 6:}
·1:表示该行代码执行了 1 次。
·-:表示未执行(如注释、空行等)。
2)结合lcov生成 HTML 报告(更直观)
bash
lcov -c -d . -o coverage.info
# 收集覆盖率数据
genhtml coverage.info -o coverage_report
# 生成 HTML 报告
·打开coverage_report/index.html查看可视化报告:
https://www.linux.com/images/stories/41373/gcov-html.png
6.2.4. Gcov 的典型应用场景
1)单元测试覆盖率检查
o确保测试用例覆盖了所有关键代码路径。
2)回归测试优化
o发现哪些代码在修改后未被测试。
3)代码质量分析
o识别冗余或无效代码(从未执行的部分)。
6.2.5. Gcov 的优缺点
1)优点
·免费且开源,集成在 GCC 中,无需额外安装。
·轻量级,适合小型到中型项目。
·支持 C/C++(GCC 编译的语言)。
2)缺点
·仅适用于 GCC,不适用于 Clang/MSVC。
·报告较原始,需结合 lcov/gcovr 生成更好看的报告。
·不能检测运行时错误(如内存泄漏),仅统计代码执行情况。
6.2.6. 替代工具
6.2.7. 总结
·Gcov是GCC自带的代码覆盖率工具,适用于 C/C++ 项目。
·基本使用流程:
(1)用-fprofile-arcs -ftest-coverage编译代码。
(2)运行程序,生成.gcda文件。
(3)用gcov生成报告,或lcov生成 HTML 可视化报告。
·适用场景:单元测试、回归测试、代码优化。
如果你需要更强大的可视化,建议结合LCOV或gcovr使用!
6.2.8 与jenkins集成
stage('gcov'){
steps {
echo "开始gcov"
sh '''
gcov -a process-process\
&&gcovr -r . --html-details -o ./html/result.html
'''
echo "结束gcov"
}
}
…
post{
always{
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'/home/jerry/googletest-main/googletest/myworkspace/process/nomal/html/',
reportFiles:'result.html',
reportName:'My Test gCover Reports',
reportTitles:'The Test gCover Report'])
}
6.3 Lcov介绍及在Jenkins中的应用
Lcov是一个基于Gcov的代码覆盖率分析工具,用于生成更直观、可视化的覆盖率报告(如 HTML)。它扩展了 Gcov 的功能,提供更友好的图形化界面,适用于C/C++项目的测试覆盖率分析。
6.3.1. Lcov 的主要功能
·支持多种覆盖率统计:
o行覆盖率(Line Coverage):代码行是否被执行。
o函数覆盖率(Function Coverage):函数是否被调用。
o分支覆盖率(Branch Coverage):条件分支(如 if-else)是否被覆盖。
·生成HTML报告,便于可视化分析。
·支持过滤数据(如排除某些目录或文件)。
·适用于大型项目,比Gcov更易于管理。
6.3.2 Lcov 的基本使用流程
1)编译代码时启用 Gcov
bash
gcc -fprofile-arcs -ftest-coverage -o my_program my_program.c
• -fprofile-arcs 和 -ftest-coverage 用于生成覆盖率数据(.gcno 文件)。
2)运行程序,生成.gcda文件
bash
./my_program
运行后,会生成.gcda文件(记录实际执行情况)。
3)使用Lcov收集覆盖率数据
bash
lcov -c -d . -o coverage.info
·-c:捕获覆盖率数据。
·-d .:从当前目录查找.gcda文件。
·-o coverage.info:输出到coverage.info文件。
4)生成 HTML 报告
bash
genhtml coverage.info -o coverage_report
·-o coverage_report:生成 HTML 报告到 coverage_report 目录。
·打开coverage_report/index.html查看报告:
https://ftp.tutorials24x7.com/uploads/1/1/1/0/111016327/lcov-report_orig.png
6.3.3. Lcov 报告示例
1)HTML 报告内容
·目录/文件列表:显示每个文件的覆盖率。
·颜色标识:
o绿色:已覆盖的代码。
o红色:未覆盖的代码。
o黄色:部分覆盖(如分支未完全覆盖)。
·详细数据:
o每行代码的执行次数。
o函数和分支的覆盖率统计。
2)终端输出示例
text
Overall coverage rate:
lines......:85.3% (100 of 117 lines)
functions..:92.1% (35 of 38 functions)
branches...:76.5% (52 of 68 branches)
6.3.4. Lcov 的高级用法
1)排除特定文件/目录
bash
lcov --remove coverage.info "/usr/include/*" "*/test/*" -o filtered.info
·--remove用于排除不需要分析的文件(如系统头文件或测试代码)。
2)合并多个覆盖率数据
bash
lcov -a coverage1.info -a coverage2.info -o combined.info
·-a用于合并多个测试运行的覆盖率数据。
3)生成 JSON 或其他格式
bash
lcov --json -o coverage.json
·可用于集成到 CI/CD 工具(如 Jenkins、GitLab CI)。
6.3.5. Lcov 的优缺点
1)优点
·可视化强:HTML 报告比 Gcov 的文本报告更直观。
·支持多种覆盖率统计(行、函数、分支)。
·适用于大型项目,可过滤无关文件。
·开源免费,与 Gcov 无缝集成。
2)缺点
·依赖 Gcov,仅适用于 GCC 编译的代码(不适用于 Clang/MSVC)。
·HTML 报告较大,可能不适合超大型项目。
·需要额外安装(部分 Linux 发行版默认不包含)。
6.3.6. Lcov 的替代工具
6.3.7. 总结
·Lcov 是 Gcov 的增强版,提供 HTML 可视化报告。
·典型使用流程:
(1)用-fprofile-arcs -ftest-coverage编译代码。
(2)运行程序,生成.gcda文件。
(3)用lcov收集数据,genhtml生成报告。
·适用场景:
oC/C++ 项目的单元测试覆盖率分析。
o持续集成(CI)中的代码质量检查。
推荐使用场景:
·如果你在用GCC + Gcov,并需要更好的可视化,Lcov 是最佳选择!
·如果项目较小,可以试试gcovr(更轻量)。
6.3.8 与jenkins集成
stage('lcov'){
steps {
echo "开始lcov"
sh '''
lcov -c -d . -o coverage.info\
&&genhtml coverage.info -o coverage_report
'''
echo "结束lcov"
}
}
…
post{
always{
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'/home/jerry/googletest-main/googletest/myworkspace/process/nomal/coverage_report/',
reportFiles:'index.html',
reportName:'My Test lCover Reports',
reportTitles:'The Test lCover Report'])
}
6.4 CPPcheck介绍及在Jenkins中的应用
6.4.1工具概述
Cppcheck是一个开源的静态代码分析工具,专门用于检测C/C++ 代码中的错误。它不依赖编译器,而是直接分析源代码,能发现许多编译器无法检测的问题(如内存泄漏、逻辑错误等)。
1主要特点
✔轻量级:比 Clang Static Analyzer 等工具更快
✔低误报率:相比部分静态分析工具更准确
✔跨平台:支持 Windows/Linux/macOS
✔可扩展:支持自定义规则
✔支持多种标准:C89/C99/C11/C++03/C++11/C++14/C++17
6.4.2. 主要检测能力
6.4.3. 基本使用方法
1)安装方法
bash
# Linux (Debian/Ubuntu)
sudo apt install cppcheck
# macOS
brew install cppcheck
# Windows
choco install cppcheck
# 或从官网下载二进制包
2)基本扫描命令
bash
# 检查单个文件
cppcheck example.cpp
# 递归检查整个项目
cppcheck --enable=all ./src/
# 输出到文件
cppcheck --output-file=report.txt main.cpp
3)常用选项
6.4.4. 高级功能
1)生成XML报告
bash
cppcheck --xml-version=2 --xml . 2> report.xml
2)与CMake集成
cmake
find_program(CPPCHECK cppcheck)
if(CPPCHECK)
add_custom_target(cppcheck
COMMAND ${
CPPCHECK}
--enable=all
--project=${
CMAKE_BINARY_DIR}/compile_commands.json
WORKING_DIRECTORY ${
CMAKE_SOURCE_DIR}
)
endif()
3)自定义规则
创建misra.json:
json
{
"script": "misra.py",
"args": ["--rule-texts=misra.txt"]
}
运行:
bash
cppcheck --addon=misra.json src/
6.4.5. 典型输出示例
text
Checking example.cpp...
[example.cpp:12]: (error) Memory leak: ptr
[example.cpp:25]: (warning) Possible null pointer dereference: p
[example.cpp:42]: (style) Variable 'i' is not used
6.4.6. 同类工具对比
6.4.7. 最佳实践建议
1)集成到CI/CD:在代码提交/合并时自动运行
2)渐进式启用:先启用基本检查,逐步增加规则
3)排除第三方代码:--suppress=:external/
4)定期更新:新版会持续改进检测能力
5)结合动态分析:与Valgrind/ASAN等工具互补使用
6.4.8. 总结
Cppcheck 是C/C++开发者工具箱中不可或缺的静态分析工具,特别适合:
·需要快速反馈的中小型项目
·资源受限的嵌入式开发环境
·作为编译警告之外的额外质量保障
推荐使用场景:
✅ 每日开发中的快速检查
✅ CI流水线中的基础质量门禁
✅ 遗留代码的质量评估
6.4.9 与jenkins集成
stage('cppcheck'){
steps {
echo "开始cppcheck"
sh '''
cppcheck --enable=all --output-file=report.html process.cpp
'''
echo "结束cppcheck"
}
}
…
post{
always{
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'/home/jerry/googletest-main/googletest/myworkspace/process/nomal/',
reportFiles:'report.html',
reportName:'Cppcheck Reports',
reportTitles:'Cppcheck Report'])
}
6.5 一个例子
6.5.1 pipeline
pipeline {
agent any
stages{
stage('gtest'){
steps {
echo "开始编译gtest"
sh '''
cd /home/jerry/googletest-main/googletest/myworkspace/process/nomal/ \
&&g++ ../../src/TestAll.cpp process.h process.cpp processTest.cpp ../../src/CallArgs.h ../../src/CallArgs.cpp -o process -lgtest -lgmock -lpthread -std=c++14 -fprofile-arcs -ftest-coverage \
&&./process --gtest_output="xml:output.xml"\
&&xsltproc ./gtest2html/gtest2html.xslt ./output.xml >./out/out.html
'''
echo "结束编译gtest"
}
}
stage('gcov'){
steps {
echo "开始gcov"
sh '''
gcov -a process-process\
&&gcovr -r . --html-details -o ./html/result.html
'''
echo "结束gcov"
}
}
stage('lcov'){
steps {
echo "开始lcov"
sh '''
lcov -c -d . -o coverage.info\
&&genhtml coverage.info -o coverage_report
'''
echo "结束lcov"
}
}
stage('cppcheck'){
steps {
echo "开始cppcheck"
sh '''
cppcheck --enable=all --output-file=report.html process.cpp
'''
echo "结束cppcheck"
}
}
stage('Code Analysis'){
steps {
echo "开始分析"
withSonarQubeEnv('SonarQube'){
sh "cd /home/jerry/googletest-main/googletest/myworkspace/process/nomal/ &&sonar-scanner"
}
echo "结束分析"
}
}
stage('Quality Gate'){
steps{
echo "开始质量分析"
script {
timeout(time:10,unit:'MINUTES'){
sleep(5)
try{
def qg = waitForQualityGate()
echo "Status: ${qg.status}"
if (qg.status != 'OK') {
echo "Status: ${qg.status}"
error "Pipeline aborted due to quality gate failure: ${qg.status}"
}
}
catch(exc){
echo "waitForQualityGate() is error"
echo "${exc}"
}
}
}
echo "结束质量分析"
}
}
}
post{
always{
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'/home/jerry/googletest-main/googletest/myworkspace/process/nomal/out/',
reportFiles:'out.html',
reportName:'My Test Reports',
reportTitles:'The Test Report'])
}
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'/home/jerry/googletest-main/googletest/myworkspace/process/nomal/',
reportFiles:'report.html',
reportName:'Cppcheck Reports',
reportTitles:'Cppcheck Report'])
}
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'/home/jerry/googletest-main/googletest/myworkspace/process/nomal/html/',
reportFiles:'result.html',
reportName:'My Test gCover Reports',
reportTitles:'The Test gCover Report'])
}
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'/home/jerry/googletest-main/googletest/myworkspace/process/nomal/coverage_report/',
reportFiles:'index.html',
reportName:'My Test lCover Reports',
reportTitles:'The Test lCover Report'])
}
}
}
}
6.5.2 总报告
6.5.3单元测试报告
6.5.4 Lcov报告
6.5.5 Gcov报告
6.5.6 Cppcheck报告