背景
基于之前wiki【gitlab搭建第一个流水线】https://blog.csdn.net/nobigdeal00/article/details/144623993
将在build阶段添加构建任务,并在test阶段添加一个测试任务
demo是一个C项目,这里选用googletest作为测试框架,googletest主要是为C++设计的,C和C++同属一脉,也可以用来测试C
安装googletest
从github克隆googletest项目
git clone https://github.com/google/googletest.git
进入googletest项目,创建构建目录,进入该目录
adminpc@adminpc:~$ cd googletest
adminpc@adminpc:~/googletest$ mkdir build
adminpc@adminpc:~/googletest$ cd build
运行CMake进行配置
adminpc@adminpc:~/googletest/build$ cmake ..
-- The C compiler identification is GNU 13.3.0
-- The CXX compiler identification is GNU 13.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Configuring done (0.4s)
-- Generating done (0.0s)
-- Build files have been written to: /home/adminpc/googletest/build
编译源码
adminpc@adminpc:~/googletest/build$ cmake --build .
[ 12%] Building CXX object googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o
[ 25%] Linking CXX static library ../lib/libgtest.a
[ 25%] Built target gtest
[ 37%] Building CXX object googlemock/CMakeFiles/gmock.dir/src/gmock-all.cc.o
[ 50%] Linking CXX static library ../lib/libgmock.a
[ 50%] Built target gmock
[ 62%] Building CXX object googlemock/CMakeFiles/gmock_main.dir/src/gmock_main.cc.o
[ 75%] Linking CXX static library ../lib/libgmock_main.a
[ 75%] Built target gmock_main
[ 87%] Building CXX object googletest/CMakeFiles/gtest_main.dir/src/gtest_main.cc.o
[100%] Linking CXX static library ../lib/libgtest_main.a
[100%] Built target gtest_main
安装googletest到系统,可以看到主要的头文件(如gtest.h)已经添加到环境变量所在路径/usr/local/include,后续写测试用例时可以直接引用该头文件
adminpc@adminpc:~/googletest/build$ sudo cmake --install .
-- Install configuration: ""
-- Up-to-date: /usr/local/include
-- Installing: /usr/local/include/gmock
-- Installing: /usr/local/include/gmock/gmock-function-mocker.h
-- Installing: /usr/local/include/gmock/gmock-more-actions.h
-- Installing: /usr/local/include/gmock/gmock-cardinalities.h
-- Installing: /usr/local/include/gmock/internal
-- Installing: /usr/local/include/gmock/internal/gmock-pp.h
-- Installing: /usr/local/include/gmock/internal/gmock-port.h
-- Installing: /usr/local/include/gmock/internal/custom
-- Installing: /usr/local/include/gmock/internal/custom/README.md
-- Installing: /usr/local/include/gmock/internal/custom/gmock-generated-actions.h
-- Installing: /usr/local/include/gmock/internal/custom/gmock-matchers.h
-- Installing: /usr/local/include/gmock/internal/custom/gmock-port.h
-- Installing: /usr/local/include/gmock/internal/gmock-internal-utils.h
-- Installing: /usr/local/include/gmock/gmock-nice-strict.h
-- Installing: /usr/local/include/gmock/gmock-actions.h
-- Installing: /usr/local/include/gmock/gmock.h
-- Installing: /usr/local/include/gmock/gmock-spec-builders.h
-- Installing: /usr/local/include/gmock/gmock-more-matchers.h
-- Installing: /usr/local/include/gmock/gmock-matchers.h
-- Installing: /usr/local/lib/libgmock.a
-- Installing: /usr/local/lib/libgmock_main.a
-- Installing: /usr/local/lib/pkgconfig/gmock.pc
-- Installing: /usr/local/lib/pkgconfig/gmock_main.pc
-- Installing: /usr/local/lib/cmake/GTest/GTestTargets.cmake
-- Installing: /usr/local/lib/cmake/GTest/GTestTargets-noconfig.cmake
-- Installing: /usr/local/lib/cmake/GTest/GTestConfigVersion.cmake
-- Installing: /usr/local/lib/cmake/GTest/GTestConfig.cmake
-- Up-to-date: /usr/local/include
-- Installing: /usr/local/include/gtest
-- Installing: /usr/local/include/gtest/gtest_pred_impl.h
-- Installing: /usr/local/include/gtest/gtest-assertion-result.h
-- Installing: /usr/local/include/gtest/gtest-spi.h
-- Installing: /usr/local/include/gtest/gtest.h
-- Installing: /usr/local/include/gtest/gtest-param-test.h
-- Installing: /usr/local/include/gtest/gtest-test-part.h
-- Installing: /usr/local/include/gtest/gtest-death-test.h
-- Installing: /usr/local/include/gtest/internal
-- Installing: /usr/local/include/gtest/internal/gtest-type-util.h
-- Installing: /usr/local/include/gtest/internal/gtest-port-arch.h
-- Installing: /usr/local/include/gtest/internal/gtest-death-test-internal.h
-- Installing: /usr/local/include/gtest/internal/gtest-filepath.h
-- Installing: /usr/local/include/gtest/internal/gtest-string.h
-- Installing: /usr/local/include/gtest/internal/gtest-internal.h
-- Installing: /usr/local/include/gtest/internal/custom
-- Installing: /usr/local/include/gtest/internal/custom/README.md
-- Installing: /usr/local/include/gtest/internal/custom/gtest.h
-- Installing: /usr/local/include/gtest/internal/custom/gtest-printers.h
-- Installing: /usr/local/include/gtest/internal/custom/gtest-port.h
-- Installing: /usr/local/include/gtest/internal/gtest-port.h
-- Installing: /usr/local/include/gtest/internal/gtest-param-util.h
-- Installing: /usr/local/include/gtest/gtest_prod.h
-- Installing: /usr/local/include/gtest/gtest-matchers.h
-- Installing: /usr/local/include/gtest/gtest-printers.h
-- Installing: /usr/local/include/gtest/gtest-typed-test.h
-- Installing: /usr/local/include/gtest/gtest-message.h
-- Installing: /usr/local/lib/libgtest.a
-- Installing: /usr/local/lib/libgtest_main.a
-- Installing: /usr/local/lib/pkgconfig/gtest.pc
-- Installing: /usr/local/lib/pkgconfig/gtest_main.pc
编写测试用例
项目路径下有四个关键文件
/project/main.c
/project/hello_world_api.c
/project/my_test.cpp
/project/CMakeLists.txt
main.c
该文件用来构建出可执行文件
#include <stdbool.h>
int PrintfHelloWorld(bool needPrintf);
int main(void)
{
return PrintfHelloWorld(true);
}
hello_world_api.c
该文件用来构建出静态库,其中提供的api可以用测试用例进行测试
#include <stdio.h>
#include <stdbool.h>
int PrintfHelloWorld(bool needPrintf)
{
if (needPrintf) {
printf("hello world\n");
return 0;
}
return 1;
}
my_test.cpp
该文件为测试用例文件,使用googletest框架进行用例编写,输出测试结果
extern "C" {
// 声明待测函数
int PrintfHelloWorld(bool needPrintf);
}
#include <gtest/gtest.h>
// 测试用例
TEST(helloWorld, needPrint) {
EXPECT_EQ(PrintfHelloWorld(true), 0);
EXPECT_EQ(PrintfHelloWorld(false), 1);
}
CMakeLists.txt
与之前wiki【gitlab搭建第一个流水线】https://blog.csdn.net/nobigdeal00/article/details/144623993里面CMakeLists.txt不同的是,添加了测试任务构建
# CMake 最低版本要求
cmake_minimum_required(VERSION 3.10)
# 项目名称和版本
project(HelloWorld VERSION 1.0)
# 查找GoogleTest
find_package(GTest REQUIRED) # 指定组件为GTest
if (NOT GTest_FOUND)
message(FATAL_ERROR "GoogleTest not found!")
endif()
# 指定 C++ 标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 添加库源文件并创建静态库
add_library(hello_world_lib STATIC hello_world_api.c)
# 添加项目源文件
add_executable(hello_world main.c)
# 将库链接到主程序
target_link_libraries(hello_world hello_world_lib)
# 添加测试源文件
add_executable(my_tests my_test.cpp)
# 链接GoogleTest库
target_link_libraries(my_tests GTest::GTest GTest::Main hello_world_lib)
# 启用测试
enable_testing()
# 添加测试命令
add_test(NAME MyTests COMMAND my_tests)
# 添加对hello_world的依赖,确保它在测试之前构建
add_dependencies(my_tests hello_world)
修改pipeline描述文件
pipeline描述文件可参考之前wiki【gitlab搭建第一个流水线】https://blog.csdn.net/nobigdeal00/article/details/144623993
这里只对构建任务build-job和测试任务unit-test-job做修改
build-job: # This job runs in the build stage, which runs first.
stage: build
script:
- echo "Compiling the code..."
- mkdir -p build && cd build
- cmake ..
- make
- echo "Compile complete."
artifacts:
paths:
- build/
expire_in: 1 week # 设置工件过期时间
tags:
- test
unit-test-job: # This job runs in the test stage.
stage: test # It only starts when the job in the build stage completes successfully.
script:
- echo "Running unit tests... This will take about 60 seconds."
- cd build
- ./my_tests
- echo "Code coverage is 90%"
dependencies:
- build-job # 明确指定依赖于build阶段,以确保获取其工件
tags:
- test
CI/CD流水线中的每个阶段(job)都是在独立的环境中运行的,默认情况下它们不会共享文件系统状态,所以这里比较关键的就是artifacts和dependencies
artifacts描述了build-job阶段构建的工件哪些要传递到下一阶段,这里指定了build目录
dependencies描述了unit-test-job阶段需要依赖哪个阶段,这里指定了build-job阶段
最终效果
提交MR,触发流水线,可看到流水线执行成功
进去看build-job详细任务,能明显看到项目的构建过程
查看unit-test-job,可以看到测试用例的执行情况,这里执行是ok的
稍微修改下hello_world_api.c里面的返回值为2,来看下测试用例失败的场景
// hello_world_api.c
#include <stdio.h>
#include <stdbool.h>
int PrintfHelloWorld(bool needPrintf)
{
if (needPrintf) {
printf("hello world\n");
return 0;
}
return 2;
}
提交MR,流水线可看到为failed状态
查看unit-test-job,可看到测试用例失败