C++代码自动化测试
Qt有 QtTest framework
🔰构建任何分支 🔰构建任何PR 🔰上传制品 👍容器化构建 (Docker)
🔰自动化测试(支持触发冒烟/单元/回归测试)
👍性能测试
👍代码覆盖率收集 🔰漏洞扫描 🔰License扫描
👍Code Lint
👍静态代码分析
👍动态代码分析 🔰Email或Slack通知
针对CI/CD流程
Minimum approvals,规避任何不经 Review 的代码进入到主分支
- 针对 Pull Request 的修改历史来分析提交历史并推荐 Reiewer;
- 通过 Lint 工具来检查编码规范;
- 通过 REST API 检查是否需要压缩 Commits 来保证清晰的提交历史;
- 通过 SonarQube 检查 Quality Gate 等。GitLab integration (sonarsource.com), Community Edition doesn’t support the analysis of multiple branches, so you can only analyze your main branch. Starting in Developer Edition, you can analyze multiple branches and merge requests.
设置docker kubernetes,GitLab runner
Test with GitLab CI/CD and generate reports in merge requests | GitLab
Improve Code Quality performance with private runners Code Quality | GitLab
code_quality:
services:
variables:
DOCKER_SOCKET_PATH: /run/user/997/docker.sock
tags:
- cq-rootless
.codeclimate.yml
Unique rules to find Bugs, Vulnerabilities, Security Hotspots, and Code Smells in your C++ code
后面考虑使用python自动化
以下针对本地
静态分析
sonarLint->vscode
插件,Running an analysis - VS Code (sonarsource.com)
cppcheck
cmake --build . --target runTestsAndSaveOutput cd build .\runTests.exe > test_results.txt
cmake --build . --target cppcheck 不能一步到位,否则没法根据cppcheck结果输出对应的txt,不过先cppcheck更合适,如何解读cppcheck?
clang-tools Docker images, clang-format 和 clang-tidy
cpp-linter
,cpp-linter-hooks也是集成到自动化流程,pip install pre-commit
,.pre-commit-config.yaml
,cpp-linter-hooks · PyPI
lint:
stage: lint
image: your-custom-image:latest # Replace with your custom image that has cpp-linter-hooks installed
script:
- cpp-linter-hooks install
- cpp-linter-hooks run
单元测试
A mock object implements the same interface as a real object
gtest gmock,都隶属于google benchmark
构建编译gtest
cmake -G "MinGW Makefiles" ..
mingw32-make
然后复制有libgmock.a libgmock_main.a libgtest.a libgtest_main.a
的lib到googletest,然后
target_include_directories(runTests PRIVATE
${CMAKE_SOURCE_DIR}/${GTEST_ROOT}/googlemock/include
${CMAKE_SOURCE_DIR}/${GTEST_ROOT}/googletest/include
${CMAKE_SOURCE_DIR}/include # 你的项目头文件目录
)
target_link_libraries(runTests
${CMAKE_SOURCE_DIR}/${GTEST_ROOT}/lib/libgtest_main.a
${CMAKE_SOURCE_DIR}/${GTEST_ROOT}/lib/libgtest.a
)
可以build/Testing/Temporary/*.log
文件审查对应的txt,或者
PS D:\codebase\mycodetest\build> .\runTests.exe > gtest_result.txt
代码覆盖率和可追溯性
- Function coverage: It’s the number of functions that have been called.
- Statement coverage: The number of statements in a program you have executed.
- Branch coverage: The number of branches you execute from the control structure (if-else, while, do while, etc.)
- Condition coverage: The number of Boolean expressions you test in your code.
- Line coverage: The number of lines you test in your source code.
.gcno & .gcda
都输出,用于HTML
lcov在win上运行不好用 pip install gcovr
吧
gcovr | C/C++ | /^TOTAL.*\s+(\d+\%)$/ |
---|
(这一步可以集成到CI/CD流程)
运行时分析
性能测试google-benchmark
,但是编译时该文件,一直报错
以下脚本可以
cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON .
不知道为什么,不能cd build
后cmake --build . --config Release
,直接在benchmark下面,但还是失败(96%),建议不要在windows上运行了
https://github.com/DigitalInBlue/Celero这个也能进行基准测试
安全测试
availability confidentiality integrity reliability robustness performance
上述有内存安全…,Fuzz Testing
SonarQube
Static Application Security Testing (SAST) Tools
Unit Testing – a checkup of the smallest functioning elements of code by a development team that is familiar with the backend.
- Component testing – a checkup of every object or part of the software separately by a testing team on the frontend.
- Integration testing – an inspection of the behavior of unit combinations.
- API testing – a segment of integration testing that focuses on API functionalities.
- Compatibility testing – an analysis of software behavior in different browsers, OS, network environments, hardware, etc.
- Smoke testing – a review of a new build aimed to prove the basic functionality (installation, launching, registration, etc.) works so that the team can move on to testing the rest of the features.
- GUI testing – a check aimed to prove that the graphic user interface meets the specifications stated in software requirements.
- End-to-end testing – an examination of the complete workflow from the beginning to the end by replicating real user scenarios.
- Regression testing – an analysis expected to verify that code changes haven’t affected untouched parts of software features after the latest iteration.
C++ 工业软件的代码测试
-
静态代码分析:使用工具如
Cppcheck
、PVS-Studio
和Coverity
等进行代码质量检查,这些工具能够发现潜在的缺陷和代码标准违规问题 。 -
单元测试:编写单元测试来验证每个模块的功能。可以使用
Google Test
或Boost.Test
等框架来自动化这一过程,并确保代码更改不会破坏现有功能 。 -
集成测试:在单元测试之后,进行集成测试以确保不同模块协同工作时的稳定性和性能。
-
系统测试:模拟真实环境对整个系统进行测试,以确保所有组件作为一个整体正常运行。
-
性能测试:使用
gperftools
或Valgrind
等工具来分析 CPU 使用和内存使用,识别性能瓶颈 。 -
内存分析:使用
valgrind
的memcheck
工具来检测内存泄漏和其他内存相关问题 。 -
异常处理:确保代码能够妥善处理异常情况,使用
try-catch
语句块来捕获和处理可能的异常 。 -
代码覆盖率:使用工具如
gcov
或lcov
来测量测试覆盖率,确保关键代码都被测试覆盖到。 -
持续集成/持续部署 (CI/CD):通过自动化的构建和部署流程,确保代码的持续质量和快速迭代。
-
遵循编码规范:如 MISRA C 标准,确保代码的可读性、可靠性和可移植性,特别是在汽车、航空航天等行业中 。
-
使用动态测试工具:如
Parasoft C++ Test
,它支持自动化测试、自定义测试用例、数据源测试用例和桩函数机制,以进行全面的动态测试 。
对于C++代码的测试流程,它通常包括单元测试、集成测试、系统测试和验收测试等多个阶段。在单元测试阶段,主要关注程序模块的正确性检验;集成测试将模块组合成系统进行测试;系统测试验证软件功能是否满足用户需求;验收测试确保软件在实际运行环境中满足业务需求 。
对于C++代码分析,有多种工具可用于进行安全、性能、内存和健壮性分析。例如,cppcheck
是一个主流的静态代码分析工具,专注于检查代码逻辑,支持内存泄漏检测等 。cpplint
则侧重于代码风格检查,确保代码符合 Google C++ Style Guide,常与 cppcheck 配合使用 。另外,PVS-Studio
是一个商业软件,提供了独特点如与 Visual Studio 集成、定时检查等 。
在内存分析方面,可以使用工具如 valgrind
、perf
和 heaptrack
。valgrind
的 memcheck
工具可以检测内存泄漏问题 。perf
作为 Linux 下的性能计数器工具,可以用于更底层的性能分析 。
性能分析工具 gperftools
为 C++ 开发者提供了分析 CPU 使用和内存使用的有效手段。通过 pprof
工具查看分析结果,可以识别程序中的性能热点和内存泄漏 。
在健壮性方面,异常处理是提高 C++ 代码健壮性和可维护性的关键技术。通过合理地处理异常,可以使程序在面对错误和异常情况时更加稳定,并能够更好地定位和解决问题 。
此外,PingCode
提到了代码的健壮性是指程序在面对错误输入、意外情况、极端环境下的适应和恢复能力。具备良好的错误处理机制、清晰的逻辑结构和充分的测试是评价代码健壮性的关键指标 。
最后,Clang
可作为静态代码分析工具使用,它可以扩展为 clang-tidy
来诊断和修复编程错误 。这些工具和方法可以帮助开发者提升C++代码的安全性、性能、内存管理和健壮性。
流程:开发过程 -> 单元测试(白盒测试)-> 集成测试 -> 系统测试(包括黑盒测试、功能测试等)
CMake是配置工具,g++/gcc是具体的编译器,CMakeLists.txt
是定义如何使用CMake的脚本
CI/CD流程中的自动化测试可以利用上述提到的测试工具(如Google Test、doctest、Catch2等)来执行单元测试、集成测试和其他类型的测试。这些测试工具可以集成到CI/CD的自动化脚本中,以确保每次代码提交都能自动运行测试。
CI/CD流程中通常会监控测试覆盖率,确保代码更改不会降低项目的测试覆盖率。测试工具可以生成覆盖率报告,这些报告可以在CI/CD流程中被收集和分析。
还有性能、代码质量门禁。。。环境一致性
source code->CMakeLists.txt->cmake->Makefile->make->executable
Makefile一般可以自己写,也可CmakeList.txt生成
Makefile基础 - Makefile教程 - 廖雪峰的官方网站 (liaoxuefeng.com)
my_project/
│
├── src/ # 源代码目录
│ ├── main.cpp
│ └── …
│
├── include/ # 头文件目录
│ ├── my_header.h
│ └── …
│
├── test/ # 测试代码目录
│ ├── test_main.cpp # 测试主函数和Google Test初始化
│ ├── test_my_header.cpp # 对my_header.h的测试
│ └── …
│
├── .gitlab-ci.yml # GitLab CI/CD配置文件
└── CMakeLists.txt # CMake配置文件,或者直接写Makefile
CMakeLists.txt示例
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 添加一个可执行文件
add_executable(my_executable src/main.cpp)
# 启用测试
enable_testing()
# 包含Google Test库
add_subdirectory(googletest)
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
# 添加测试可执行文件
add_executable(tests test/test_main.cpp test/test_my_header.cpp)
target_link_libraries(tests gtest_main)
# 添加测试
add_test(NAME MyTests COMMAND tests)
.gitlab-ci.yml示例
stages:
- build
- test
variables:
CMAKE_BUILD_TYPE: "Release"
build_job:
stage: build
script:
- cmake -S . -B build
- cmake --build build
test_job:
stage: test
script:
- cmake --build build --target tests
- ./build/tests
dependencies:
- build_job
allow_failure: false
test_my_header.cpp示例
#include <gtest/gtest.h>
#include "my_header.h"
// 测试 add 函数
TEST(MyHeaderTest, AddTest) {
EXPECT_EQ(add(1, 2), 3);
EXPECT_EQ(add(-1, 1), 0);
EXPECT_EQ(add(-1, -1), -2);
}
// 测试 minus 函数
TEST(MyHeaderTest, MinusTest) {
EXPECT_EQ(minus(5, 3), 2);
EXPECT_EQ(minus(-1, -1), 0);
EXPECT_EQ(minus(1, 2), -1);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
MakeFile与CI/CD
在CI/CD配置文件中添加静态代码分析工具的步骤与Makefile有以下关系:
-
互补角色:
- Makefile 主要用于本地或开发环境中的构建和测试自动化。
- CI/CD配置文件定义了在持续集成/持续部署服务器上的自动化流程。
-
构建触发:
- 在Makefile中,您可以定义如何构建项目和运行测试。
- 在CI/CD配置文件中,您可以设置在代码提交或拉取请求时自动触发Makefile中的构建和测试。
-
扩展流程:
- Makefile通常不包含静态代码分析步骤,因为它主要关注构建过程。
- CI/CD配置文件可以扩展构建流程,包括在构建前后运行额外的步骤,如静态代码分析。
-
环境差异:
- Makefile在开发人员的本地机器上运行,可能无法访问CI/CD环境中的特定工具或服务。
- CI/CD配置文件在服务器上执行,可以安装和配置所需的任何工具,包括静态代码分析工具。
-
报告和通知:
- Makefile可以生成构建和测试报告,但通常不负责将报告发送给团队成员。
- CI/CD配置文件可以集成通知系统,在静态代码分析或其他步骤失败时发送电子邮件或Slack消息给团队。
-
依赖管理:
- Makefile管理项目文件的依赖关系,确保正确的文件在正确的时间被重新构建。
- CI/CD配置文件管理整个项目构建和部署过程中的依赖,包括依赖项的安装和配置。
-
工作流集成:
- 在CI/CD配置文件中添加静态代码分析步骤后,您可以在Makefile中调用这些步骤或脚本,以确保它们作为构建流程的一部分被执行。
例如,如果您在CI/CD配置文件中添加了cppcheck
分析步骤,您可能会在Makefile中添加一个类似的规则来运行它,如下所示:
# 定义静态代码分析目标
lint:
cppcheck --enable=all --inconclusive --verbose src/
# 添加lint作为默认目标的依赖
all: lint $(TARGET)
这样,当您在本地运行make
时,lint
目标将作为构建流程的一部分自动执行,提供与CI/CD服务器上相同的分析步骤。
总之,Makefile和CI/CD配置文件共同工作,确保代码在开发过程中和部署到生产环境之前都经过了彻底的检查和测试。Makefile关注本地构建和测试,而CI/CD配置文件扩展了整个流程,包括静态代码分析和其他自动化步骤。
1. CSD角度
持续软件开发是一种软件开发实践,强调在整个开发周期中持续地集成和测试代码。在C++项目中,自动化测试可以集成到CSD流程中,以确保代码质量。以下是一些关键点:
- 持续集成(CI): 自动化测试可以作为持续集成流程的一部分,每次代码提交后自动运行测试,快速发现集成问题。
- 测试覆盖率: 使用工具(如gcov、lcov)来监控测试覆盖率,确保代码的关键部分得到充分测试。
- 自动化测试框架: 集成如Google Test、Boost.Test等C++测试框架,编写和执行单元测试、集成测试。
- 代码质量分析: 结合静态代码分析工具(如Cppcheck、Clang-Tidy)来自动检测代码质量问题。
- 测试驱动开发(TDD): 鼓励开发团队采用测试驱动的开发模式,先编写测试,再编写功能代码。
- 回归测试: 自动化测试帮助维护一个健壮的回归测试套件,确保新代码不会破坏现有功能。
2.Makefile角度
Makefile是自动化构建系统中的核心组件,用于定义如何编译和链接程序。在C++项目中,Makefile可以配置自动化测试流程。以下是一些关键点:
- 构建规则: 在Makefile中定义规则来编译测试代码和可执行文件。
- 依赖管理: 明确指定源文件和头文件的依赖关系,确保在源文件更改时,相关的测试用例能够被重新编译。
- 测试执行: 定义make目标来运行测试,可以是单个测试用例或整个测试套件。
- 并行测试: 利用make的并行执行特性来同时运行多个测试,加快测试过程。
- 测试结果: 收集和报告测试结果,可以在Makefile中集成工具来生成测试报告。
- 清理规则: 提供清理构建和测试生成的文件的规则,保持工作目录的整洁。
- 自定义变量: 使用Makefile中的变量来自定义测试配置,如选择不同的编译器标志或测试选项。
- Makefile 主要参与构建过程,意味着它定义了如何编译和链接程序,以及如何管理和执行构建过程中的各种任务。Makefile 通过指定依赖关系和规则来指导
make
工具按正确的顺序执行任务。
Makefile 主要参与构建过程,意味着它定义了如何编译和链接程序,以及如何管理和执行构建过程中的各种任务。Makefile 通过指定依赖关系和规则来指导 make
工具按正确的顺序执行任务。
构建过程的组成部分:
- 编译源代码文件:将
.cpp
文件编译成.o
对象文件。 - 链接对象文件:将多个
.o
文件链接成一个可执行文件或库文件。 - 生成文档:从源代码中提取注释并生成文档。
- 运行测试:编译并执行单元测试或集成测试。
- 清理构建产物:删除所有编译生成的文件,以便重新构建。
举例说明 Makefile 的构建过程:
假设您有一个简单的 C++ 项目,包含以下文件:
src/main.cpp
:主程序源文件。src/utils.cpp
和src/utils.h
:辅助功能实现和声明。include/app.h
:应用程序接口声明。
您的 Makefile 可能如下所示:
# 定义编译器和链接器
CC=g++
CXXFLAGS=-Iinclude -Wall -Wextra -std=c++17
LDFLAGS=
# 定义目标应用程序名称
APP_NAME=app
# 收集所有源文件和对象文件
SRC=$(wildcard src/*.cpp)
OBJ=$(SRC:src/%.cpp=build/%.o)
# 默认目标
all: $(APP_NAME)
# 应用程序依赖于所有对象文件
$(APP_NAME): $(OBJ)
$(CC) $(LDFLAGS) -o $@ $^
# 每个对象文件依赖于其对应的源文件
build/%.o: src/%.cpp
mkdir -p build
$(CC) $(CXXFLAGS) -c $< -o $@
# 清理所有构建文件
clean:
rm -rf build $(APP_NAME)
# 伪目标声明
.PHONY: all clean
在这个 Makefile 中:
all
目标是默认目标,当您运行make
时,它会构建应用程序。$(APP_NAME)
目标定义了如何从对象文件生成最终的可执行文件。$(OBJ)
是从src/
目录下所有.cpp
文件生成的对象文件列表。build/%.o
规则定义了如何编译单个源文件生成对应的对象文件。clean
目标用于清理构建产物,以便您可以从头开始构建。
当您在项目根目录下运行 make
命令时,Makefile 会根据定义的规则和依赖关系执行以下构建过程:
- 如果
build/
目录不存在,make
会创建它。 make
会编译src/main.cpp
和src/utils.cpp
,生成对应的.o
文件。make
会链接所有.o
文件成为最终的app
可执行文件。- 如果您运行
make clean
,make
会删除build/
目录和app
可执行文件,让您可以进行一次干净的构建。
Makefile 通过这种方式管理构建过程,确保源代码正确编译和链接,同时提供清理和其他辅助功能。
在实际应用中,可以将CSD的自动化测试理念与Makefile的构建能力结合起来,实现一个强大的自动化测试流程。例如:
-
在CSD的CI流程中,触发Makefile来编译和运行测试。
-
使用Makefile的规则来调用CSD中的代码质量分析工具。
-
通过Makefile生成的测试报告反馈到CSD的报告系统中,供团队成员查看和分析。
测试工具与CI/CD的关系:
-
自动化测试执行:CI/CD流程中的自动化测试可以利用上述提到的测试工具(如Google Test、doctest、Catch2等)来执行单元测试、集成测试和其他类型的测试。这些测试工具可以集成到CI/CD的自动化脚本中,以确保每次代码提交都能自动运行测试。
-
快速反馈:CI/CD的目标之一是提供快速反馈。当开发者提交代码更改时,自动化测试可以迅速执行,帮助团队尽早发现问题。测试工具的集成使得这一过程更加高效。
-
测试覆盖率:CI/CD流程中通常会监控测试覆盖率,确保代码更改不会降低项目的测试覆盖率。测试工具可以生成覆盖率报告,这些报告可以在CI/CD流程中被收集和分析。
-
性能监控:对于性能敏感的应用,可以使用Google Benchmark等工具在CI/CD流程中监控性能指标。如果性能下降超过某个阈值,CI/CD流程可以标记构建为失败,防止性能退化的代码被合并或部署。
-
代码质量门禁:CI/CD流程中可以设置代码质量门禁(Quality Gates),只有当代码满足一定的质量标准(如测试通过率、代码风格检查等)时,代码才能被合并或部署。测试工具的输出可以作为质量门禁的判断依据。
-
持续改进:CI/CD流程鼓励持续改进。通过集成测试工具,团队可以持续收集测试结果和性能数据,分析趋势,并根据这些信息进行代码和测试的优化。
-
环境一致性:CI/CD流程通常在一致的环境中运行测试,这有助于减少“它在我机器上可以运行”的问题。测试工具可以在这个标准化的环境中运行,确保测试结果的可靠性。
-
文档和报告:CI/CD流程可以生成详细的测试报告,包括测试结果、失败的测试用例、性能数据等。这些报告可以作为文档的一部分,帮助团队了解代码更改的影响。
总之,测试工具是CI/CD流程中不可或缺的一部分,它们帮助自动化测试过程,提高软件质量,加快开发速度,并提供必要的反馈和报告,以支持持续改进。通过将测试工具与CI/CD流程紧密结合,团队可以更有效地管理和维护代码库。
CSD中,Makefile集成到CI流程
1. CSD的CI流程,触发Makefile编译和运行测试
CI流程触发:
- 当代码被推送到版本控制系统(如Git)时,CI服务器(如Jenkins, Travis CI, GitHub Actions等)自动触发构建流程。
Makefile集成:
- 在项目的根目录下,存在一个Makefile文件,它定义了项目的构建规则和目标。
- 一个典型的Makefile会包含编译源代码、生成可执行文件、运行测试等规则。
2. 用Makefile的规则调用CSD中的代码质量分析工具
代码质量分析工具:
- 工具如Cppcheck、Clang-Tidy、Coverity等,可以集成到Makefile中。
Makefile集成代码分析:
- 在Makefile中添加规则来运行代码质量分析工具,并生成报告。
示例Makefile规则:
analyze:
clang-tidy $(SRC_FILES) --checks=*,-google-*,-cppcoreguidelines-*
analyze
目标运行Clang-Tidy工具对源文件进行静态代码分析。
3. 通过Makefile生成的测试报告反馈到CSD的报告系统
测试报告生成:
- 测试框架(如Google Test)可以生成测试结果的详细报告。
集成到Makefile:
- 在Makefile中添加规则来收集测试结果,并可能使用工具(如Allure, ReportGenerator)生成更易读的报告。
示例Makefile规则:
test_report:
./test_runner
generate_test_report.sh test_output.xml > test_report.html
send_report:
curl -X POST -F "file=@test_report.html" https://your-csd-report-system.com/upload
test_report
目标运行测试并生成测试报告。send_report
目标将测试报告上传到CSD的报告系统。
CSD报告系统集成:
- CI服务器配置为在构建完成后,将报告上传到CSD的报告系统。
- 报告系统可以是团队内部的系统,也可以是第三方服务。
-
-
针对C++项目,以下是每种测试方法的具体应用和工具推荐:
-
单元测试:
- 选择一个测试框架,如 Google Test。
- 使用
TEST
或TEST_F
宏来编写测试用例。 - 确保测试用例覆盖所有函数的边界条件、异常情况和预期行为。
-
集成测试:
- 使用 CMake 来定义项目结构和构建配置。
- 利用 CMake 的测试驱动程序(如 CTest)来组织和执行集成测试。
-
系统测试:
- 对于桌面应用,可以使用 CppUnit 或 Google Test 编写端到端的测试脚本。
- 模拟用户交互,测试应用的完整工作流程。
-
性能测试:
- 使用 Google Benchmark 来创建性能测试,测量函数执行时间。
- 分析循环迭代次数、内存使用等性能指标。
-
安全性测试:
- 虽然 C++ 没有直接的安全性测试工具,但可以使用静态代码分析工具来检测潜在的安全漏洞。
-
可用性测试:
- 通过用户测试会议或反馈问卷,收集用户对软件界面和操作流程的反馈。
-
回归测试:
- 利用自动化测试框架定期运行单元测试和集成测试,确保新代码没有破坏旧功能。
-
兼容性测试:
- 使用 Wine(在Linux上运行Windows应用)或虚拟机来测试不同操作系统下的兼容性。
-
灾难恢复测试:
- 编写测试脚本来模拟数据损坏或丢失,验证恢复机制的有效性。
-
代码审查:
- 使用 GitHub Pull Requests、GitLab Merge Requests 或 Phabricator 进行代码审查。
-
静态代码分析:
- 使用 Clang Static Analyzer、Cppcheck 或 Coverity 来分析代码质量。
-
动态分析:
- 使用 Valgrind 检测内存泄漏和线程问题。
- 使用 GDB 或 LLDB 进行运行时调试。
-
用户验收测试:
- 让目标用户群体测试软件,确保功能满足用户的实际需求。
-
持续集成测试:
- 设置 Jenkins、Travis CI 或 GitLab CI 与 CMake 集成,自动化构建和测试。
-
负载测试:
- 使用压力测试工具,如 Apache Bench(ab)或 wrk,模拟高并发请求。
-
端到端测试:
- 对于C++应用,可能需要使用自动化测试工具,如 Selenium(如果应用有Web界面)或自定义脚本来模拟用户操作。
-
-
设置C++项目的CI/CD流程
1. 准备工作
- 了解项目:熟悉项目结构和Makefile,了解编译和链接过程。
- 安装GitLab Runner:确保您的GitLab实例配置了Runner,它将执行CI/CD作业。
2. 编写.gitlab-ci.yml
3. 语法和风格检查(Lint)
- 工具:
cppcheck
或clang-tidy
- 配置:在
.gitlab-ci.yml
的lint
阶段中添加检查命令。
4. 编译项目
- 工具:使用项目的Makefile
- 配置:在
.gitlab-ci.yml
的build
阶段中添加make
命令。
5. 单元测试和逻辑测试
- 工具:Google Test、Boost.Test或其他C++测试框架
- 编写测试代码:为关键功能编写测试用例。
- 配置:在Makefile中添加
test
目标,并在.gitlab-ci.yml
的test
阶段中运行make test
。
6. 集成测试
- 编写集成测试:测试模块间的交互。
- 配置:可能需要在Makefile中添加特定的集成测试目标。
7. 性能测试
- 工具:Valgrind、gprof或其他性能分析工具
- 配置:在CI流程中添加性能测试阶段,运行性能测试命令。
8. 代码覆盖率
- 工具:gcov、lcov
- 配置:运行测试后,使用这些工具生成覆盖率报告,并在
.gitlab-ci.yml
中配置为artifacts。
9. 代码审查
- 人工审查:鼓励团队成员进行代码审查。
- 自动化工具:可以使用ESLint、Stylelint等工具进行代码风格审查。
10. 部署(如果需要)
- 配置:在CI流程中添加部署阶段,自动化部署到测试或生产环境。
11. 持续集成触发
- 提交代码:每次提交或合并请求时,GitLab Runner将自动触发CI流程。
12. 监控和报告
- 使用GitLab UI:监控测试执行情况和结果。
- 配置通知:设置电子邮件或其他通知,以便在测试失败时收到通知。
13. 文档和维护
- 文档化:记录CI/CD流程和测试策略。
- 维护:定期回顾和更新CI/CD配置和测试代码。
示例:使用cppcheck进行静态分析
- 安装cppcheck:通过包管理器安装。
- 运行cppcheck:在
.gitlab-ci.yml
中添加一个lint阶段,并运行cppcheck
命令。
测试一般流程:
-
代码编写:开发者编写代码,并可能在本地运行测试和静态分析。
-
提交和推送:开发者将更改提交到Git仓库,并推送到远程仓库(如GitLab)。
-
触发CI/CD:推送操作触发GitLab CI/CD流程。
4. 运行
.gitlab-ci.yml
:.gitlab-ci.yml
是一个配置文件,定义了GitLab CI/CD的流程。它告诉GitLab如何构建、测试、分析和部署代码。这个文件通常包含以下几个部分:- stages:定义了CI/CD的各个阶段,如
build
、test
、deploy
等。 - jobs:定义了在每个阶段要执行的具体任务。
- script:指定了每个任务要运行的命令序列。
- artifacts:定义了CI/CD过程中生成的文件,如测试报告、构建产物等,这些文件可以在GitLab界面上下载查看。
- cache:定义了需要被缓存的文件或目录,以加速构建过程。
5. 编译和构建:
Makefile是一个构建自动化工具,它定义了一系列的规则和依赖关系来编译和链接源代码。一个典型的Makefile可能包含:
- 目标:通常是构建产物,如可执行文件或库文件。
- 依赖:目标文件依赖的源文件或其他目标。
- 命令:生成目标所需的shell命令。
例如,一个简单的Makefile可能如下所示:
all: my_program my_program: main.o utility.o g++ -o my_program main.o utility.o main.o: main.cpp g++ -c main.cpp utility.o: utility.cpp g++ -c utility.cpp clean: rm -f my_program *.o
在这个Makefile中:
all
是默认目标,依赖于my_program
。my_program
的构建依赖于main.o
和utility.o
两个对象文件。main.o
和utility.o
的生成依赖于相应的.cpp
源文件。clean
是一个伪目标,用于清理构建产物。
6. 静态代码分析(可以转到yml):
静态代码分析是在不运行代码的情况下检查代码质量的工具。它可以检测出潜在的错误、代码风格问题、复杂度过高的函数等。在
.gitlab-ci.yml
中,你可以添加一个步骤来运行静态分析工具,例如:analyze: script: - cppcheck --enable=all --inconclusive --verbose cppcheck_output.xml . artifacts: reports: cppcheck: cppcheck_output.xml
在这个例子中:
analyze
是一个job,它运行cppcheck
工具。script
定义了要执行的命令。artifacts
定义了如何保存分析报告。
7. 测试:
单元测试是验证代码单个部分(如函数或类)是否按预期工作的测试。使用Catch2这样的测试框架,你可以编写测试用例并运行它们来验证代码功能。在
.gitlab-ci.yml
中,你可以定义一个job来运行这些测试:test: script: - ./run_tests
在这个例子中:
test
是一个job,它运行run_tests
脚本或可执行文件,这个文件负责执行所有的测试用例。
在代码层面,一个Catch2的测试用例可能如下所示:
#define CATCH_CONFIG_MAIN #include "catch.hpp" #include "my_header.h" TEST_CASE("Addition") { SECTION("Add two positive numbers") { REQUIRE(add(2, 3) == 5); } SECTION("Add two negative numbers") { REQUIRE(add(-1, -2) == -3); } SECTION("Add positive and negative numbers") { REQUIRE(add(-1, 2) == 1); } }
在这个测试用例中:
TEST_CASE
定义了一个测试案例,它包含多个SECTION
。REQUIRE
是一个断言宏,用于验证函数的返回值是否符合预期。
这些步骤结合起来,形成了一个完整的CI/CD流程,从代码提交到自动化测试和分析,再到可能的部署,确保了代码质量和快速反馈。
8.报告:生成测试报告和静态分析报告。
9.合并请求:如果所有检查都通过,开发者可以创建一个合并请求将更改合并到主分支。
10.部署:在合并到主分支后,CI/CD流程可能自动部署代码到生产环境或测试环境。
11.反馈循环:开发者根据CI/CD流程中的反馈进行必要的调整。
- stages:定义了CI/CD的各个阶段,如
1. 配置 .gitlab-ci.yml
在项目的根目录下创建或更新 .gitlab-ci.yml
文件,定义你的 CI/CD 流程。例如:
yamlstages:
- test
test_job:
stage: test
script:
- echo "运行测试脚本"
- make test # 假设你的测试命令是 make test
only:
- merge_requests
except:
- branches # 这会跳过对分支的直接提交,只对 MR 运行测试
这个配置会在每次创建 Merge Request 时运行 test_job
,但不会在直接推送到分支时运行。
2. 设置保护规则
在 GitLab 的项目设置中,你可以为分支设置保护规则,以防止不合格的代码被合并。
- 进入你的项目设置页面。
- 选择 “Repository” > “Protected Branches”。
- 选择你想要保护的分支(通常是
main
或master
)。 - 启用 “Allow only merge requests to be merged” 选项,这样只有通过 Merge Request 才能合并代码。
3. 配置 Merge Request 规则
在 GitLab 的项目设置中,你可以设置 Merge Request 规则,要求所有 MR 必须通过所有配置的 CI 测试。
- 进入 “Settings” > “Merge Requests”。
- 找到 “Pipeline must succeed” 选项并启用它。
- 选择 “test_job” 作为必须成功的作业。
4. 编写测试代码
确保你的项目中有适当的测试代码,并且它们能够覆盖关键功能和边界条件。
5. 提交和推送代码
开发者需要按照以下步骤提交代码:
- 将他们的更改推送到一个新分支。
- 创建一个 Merge Request,将他们的分支合并到受保护的分支。
6. 运行 CI/CD 测试
当开发者提交 Merge Request 时,GitLab CI 将自动运行 .gitlab-ci.yml
中定义的测试作业。
7. 审查和合并
- 测试通过后,代码被认为是合格的,可以被合并。
- 如果测试失败,开发者需要修复问题并重新推送更改,直到测试通过。
注意事项
- 确保所有开发者都了解 CI/CD 流程和测试的重要性。
- 测试作业应该尽可能快速和全面,以避免长时间的等待和不必要的合并阻塞。
- 考虑使用 GitLab 的 “Review Apps” 功能,为每个 MR 生成一个可访问的应用程序实例,以便于测试和审查。
通过基础设施即代码(Infrastructure as Code, IaC)、持续集成/持续部署(CI/CD)和容器化技术来实现高效的开发和部署流程。以下是一个详细的逐步指南,使用 Terraform、GitLab CI、Docker 和 Kubernetes 来实现这一目标。
1. 定义基础设施需求
首先,使用 Terraform 定义你的基础设施,包括VPS、数据库实例等。
Terraform 配置(例如 main.tf
):
provider "aws" {
region = "us-west-2"
}
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}
resource "aws_db_instance" "default" {
allocated_storage = 20
storage_type = "gp2"
engine = "mysql"
engine_version = "5.7"
instance_class = "db.t2.micro"
name = "mydb"
username = var.db_username
password = var.db_password
parameter_group_name = "default.mysql5.7"
}
variable "db_username" {}
variable "db_password" {}
确保包含敏感信息的变量在 terraform.tfvars
(非版本控制下)中定义:
db_username = "yourusername"
db_password = "yourpassword"
2. 编写代码
在你的本地开发环境中编写 C++ 代码,并确保代码符合预期的 IaC 基础架构配置需求。
3. 提交到 GitLab
将代码和 Terraform 配置文件提交到 GitLab 仓库:
git add .
git commit -m "Initial commit with C++ code and Terraform configuration"
git push origin main
4. GitLab Runner 触发 CI/CD 流程
在 GitLab CI/CD 流程中使用 Terraform 来管理基础设施。
.gitlab-ci.yml
配置:
stages:
- setup_infrastructure
- build
- test
- build_docker
- deploy
variables:
TF_STACK: "my-stack"
setup_infrastructure:
stage: setup_infrastructure
image: hashicorp/terraform:latest
before_script:
- terraform --version
script:
- terraform init
- terraform plan -out=tfplan
- terraform apply -input=false tfplan
build:
stage: build
script:
- mkdir build
- cd build
- cmake ..
- make
test:
stage: test
script:
- cd build
- ctest
build_docker:
stage: build_docker
image: docker:latest
services:
- docker:dind
script:
- docker build -t myapp:latest .
- docker tag myapp:latest registry.gitlab.com/yourusername/yourrepo:latest
- docker push registry.gitlab.com/yourusername/yourrepo:latest
deploy:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl apply -f k8s/deployment.yaml
5. 编译
在 GitLab CI 的 build
阶段使用 cmake
和 make
编译你的 C++ 项目。
6. 单元测试、性能测试、代码质量分析
在 test
阶段运行单元测试,可以扩展到包含性能测试和代码质量分析。
单元测试的 .gitlab-ci.yml
部分:
test:
stage: test
script:
- cd build
- ctest
7. 构建 Docker 镜像
在 build_docker
阶段构建并推送 Docker 镜像。
示例 Dockerfile
:
FROM ubuntu:20.04
COPY . /app
WORKDIR /app
RUN apt-get update && apt-get install -y cmake make g++
RUN mkdir build && cd build && cmake .. && make
CMD ["./build/your_project_executable"]
8. 部署到 Kubernetes
使用 Kubernetes 的 YAML 配置文件来定义Pod、Service等,并在 deploy
阶段中应用这些配置。
示例 Kubernetes 配置 k8s/deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: registry.gitlab.com/yourusername/yourrepo:latest
ports:
- containerPort: 8080
9. 配置管理
使用 Terraform 或其他 IaC 工具来管理和保持 Kubernetes YAML 文件的一致性。
10. 持续监控和调整
利用 IaC 工具来监控基础设施状态,并根据CI/CD流程中收集的反馈自动进行调整。
例如使用 Prometheus 和 Grafana进行监控:
在Terraform配置中包含这些监控工具的部署,也可以独立管理它们。
例如,如果你使用 Terraform 作为 IaC 工具,你的 CI/CD 流程中可能会加入如下步骤:
-
在 GitLab 的
.gitlab-ci.yml
文件中添加 Terraform 初始化和部署的步骤:deploy: script: - terraform init - terraform plan - terraform apply -auto-approve
-
确保
deploy
步骤在代码提交后自动执行,同时也确保 Terraform 配置文件已经包含了创建和管理 Kubernetes 资源的定义。
为了实现高度自动化的CI/CD流程,减少人为干预,我们可以加入更多的细节,包括:
- 自动化的基础设施配置和管理,使用 Terraform
- 详细的代码质量和测试集成,包括 Google Test, Google Mock 和 SonarQube
- 完整的Docker镜像构建和Kubernetes部署
- 灾难恢复和监控
以下是具体的实现步骤和细节:
1. 基础设施即代码 (IaC) - 使用 Terraform
确保Terraform脚本可以自动化创建所有需要的基础设施。这包括配置VPS、数据库实例等。
main.tf
例子:
provider "aws" {
region = "us-west-2"
}
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "MyInstance"
}
}
resource "aws_db_instance" "default" {
allocated_storage = 20
storage_type = "gp2"
engine = "mysql"
engine_version = "5.7"
instance_class = "db.t2.micro"
name = "mydb"
username = var.db_username
password = var.db_password
parameter_group_name = "default.mysql5.7"
}
variable "db_username" {}
variable "db_password" {}
变量文件 terraform.tfvars
(这个文件应该不被版本控制):
db_username = "yourusername"
db_password = "yourpassword"
2. C++ 项目配置
CMakeLists.txt
确保项目能够使用CMake进行构建,并且集成Google Test和Google Mock。
cmake_minimum_required(VERSION 3.10)
project(YourProject)
set(CMAKE_CXX_STANDARD 14)
# 添加源文件
file(GLOB_RECURSE SOURCES "src/*.cpp")
add_library(YourProjectLibrary ${SOURCES})
# GoogleTest 和 GoogleMock 的配置
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/release-1.10.0.zip
)
FetchContent_MakeAvailable(googletest)
enable_testing()
file(GLOB TEST_SOURCES "tests/*.cpp")
add_executable(YourProjectTests ${TEST_SOURCES})
target_link_libraries(YourProjectTests gtest gmock gtest_main)
add_test(NAME YourProjectTests COMMAND YourProjectTests)
Google Test 和 Google Mock 示例
tests/test_your_project_code.cpp
:
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "your_project_code.h"
class MockYourClass : public YourClass {
public:
MOCK_METHOD(int, add, (int a, int b), (override));
};
TEST(YourTestClass, YourTestFunctionWithMock) {
MockYourClass mock;
EXPECT_CALL(mock, add(1, 1)).WillOnce(::testing::Return(2));
EXPECT_EQ(mock.add(1, 1), 2);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
3. GitLab CI/CD 配置
以下是一个更完整的 .gitlab-ci.yml
配置,包含自动化代码质量分析、测试和部署。
stages:
- setup_infrastructure
- build
- test
- code_quality
- build_docker
- deploy
variables:
TF_STACK: "my-stack"
SONAR_HOST_URL: "http://your-sonarqube-url"
SONAR_TOKEN: "${SONAR_TOKEN}" # 将 SonarQube 的 token 设置为 GitLab CI 的 Secret
cache:
paths:
- build-wrapper-output
setup_infrastructure:
stage: setup_infrastructure
image: hashicorp/terraform:latest
before_script:
- terraform --version
script:
- terraform init
- terraform plan -out=tfplan
- terraform apply -input=false tfplan
build:
stage: build
script:
- mkdir -p build
- cd build
- cmake ..
- make
test:
stage: test
script:
- cd build
- ./YourProjectTests
code_quality:
stage: code_quality
image: sonarsource/sonar-scanner-cli
script:
- sonar-scanner
-Dsonar.projectKey=your_project_key
-Dsonar.sources=src
-Dsonar.tests=tests
-Dsonar.language=cpp
-Dsonar.sourceEncoding=UTF-8
-Dsonar.host.url=$SONAR_HOST_URL
-Dsonar.login=$SONAR_TOKEN
artifacts:
paths:
- .scannerwork
build_docker:
stage: build_docker
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}
script:
- docker build -t ${CI_REGISTRY_IMAGE}:latest .
- docker push ${CI_REGISTRY_IMAGE}:latest
deploy:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl apply -f k8s/deployment.yaml
Dockerfile
配置 Dockerfile 以便于在 GitLab CI 中进行构建和推送。
Dockerfile
:
FROM ubuntu:20.04
# 安装必备的构建工具
RUN apt-get update && apt-get install -y \
cmake \
make \
g++ \
libgtest-dev \
&& apt-get clean
# 安装 GoogleTest
RUN cd /usr/src/gtest && cmake . && make && cp *.a /usr/lib
COPY . /app
WORKDIR /app
RUN mkdir -p build && cd build && cmake .. && make
CMD ["./build/your_project_executable"]
4. Kubernetes 配置
示例 Kubernetes 配置 k8s/deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: registry.gitlab.com/yourusername/yourrepo:latest
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
5. 灾难恢复和监控
你可以使用 Prometheus 和 Grafana 进行持续监控,也可以使用Terraform管理这些监控服务。
Prometheus Terraform 配置:
resource "helm_release" "prometheus" {
name = "prometheus"
repository = "https://prometheus-community.github.io/helm-charts"
chart = "prometheus"
values = [
<<EOF
server:
resources:
limits:
cpu: 0.5
memory: 512Mi
requests:
cpu: 0.1
memory: 128Mi
EOF
]
}
Grafana Terraform 配置:
resource "helm_release" "grafana" {
name = "grafana"
repository = "https://grafana.github.io/helm-charts"
chart = "grafana"
values = [
<<EOF
adminUser: "admin"
adminPassword: "admin"
EOF
]
}
s 配置
示例 Kubernetes 配置 k8s/deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: registry.gitlab.com/yourusername/yourrepo:latest
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
5. 灾难恢复和监控
你可以使用 Prometheus 和 Grafana 进行持续监控,也可以使用Terraform管理这些监控服务。
Prometheus Terraform 配置:
resource "helm_release" "prometheus" {
name = "prometheus"
repository = "https://prometheus-community.github.io/helm-charts"
chart = "prometheus"
values = [
<<EOF
server:
resources:
limits:
cpu: 0.5
memory: 512Mi
requests:
cpu: 0.1
memory: 128Mi
EOF
]
}
Grafana Terraform 配置:
resource "helm_release" "grafana" {
name = "grafana"
repository = "https://grafana.github.io/helm-charts"
chart = "grafana"
values = [
<<EOF
adminUser: "admin"
adminPassword: "admin"
EOF
]
}