You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CMake中单元测试分组构建与目标执行控制问题咨询

CMake单元测试配置问题解答

问题背景

我在CMake中配置了多个测试构建目标,最后一个目标UTestAll用于运行所有测试。请问:

  1. UTestAll是否会单独构建每个单元测试?若是,是否会导致同一测试被多次构建?有没有办法对单元测试进行分组,使其仅构建一次?
  2. 是否可以设置选项排除特定目标的执行?例如在Jenkins流水线中不运行UTestAll,但在本地运行该目标。

现有CMake代码片段

Test1

set(THIS UTest1)
string(TOUPPER DO_BUILD_${THIS} THIS_FLAG)

if (${THIS_FLAG})
  add_executable(
          ${THIS}
          src/Test1.cpp
  )

  target_include_directories(${THIS} PRIVATE include)
  target_link_libraries(${THIS} PUBLIC lib1)
endif()

Test2

set(THIS UTest2)
string(TOUPPER DO_BUILD_${THIS} THIS_FLAG)

if (${THIS_FLAG})
  add_executable(
          ${THIS}
          src/Test2.cpp
  )

  target_include_directories(${THIS} PRIVATE include)
  target_link_libraries(${THIS} PUBLIC lib2)
endif()

Test3

set(THIS UTest3)
string(TOUPPER DO_BUILD_${THIS} THIS_FLAG)

if (${THIS_FLAG})
  add_executable(
          ${THIS}
          src/Test3.cpp
  )

  target_include_directories(${THIS} PRIVATE include)
  target_link_libraries(${THIS} PUBLIC lib3)
endif()

Run ALL Tests

set(THIS UTestAll)
string(TOUPPER DO_BUILD_${THIS} THIS_FLAG)

if (${THIS_FLAG})
  add_executable(
          ${THIS}
          src/Test1.cpp
          src/Test2.cpp
          src/Test3.cpp
  )

  target_include_directories(${THIS} PRIVATE include)
  target_link_libraries(${THIS} PUBLIC lib1 lib2 lib3)
endif()

问题1解答

当前的UTestAll实现会导致重复构建:

  • 若同时开启DO_BUILD_UTEST1和DO_BUILD_UTESTALL,src/Test1.cpp会被编译两次——一次生成UTest1可执行文件,另一次生成UTestAll。Test2、Test3的源文件同理,会造成构建资源浪费。

解决办法

方案1:封装测试代码为静态库

将每个测试的核心逻辑抽成静态库,单个测试目标和UTestAll都链接这些库,源文件仅编译一次:

# 创建测试静态库
add_library(Test1Lib STATIC src/Test1.cpp)
target_include_directories(Test1Lib PRIVATE include)
target_link_libraries(Test1Lib PUBLIC lib1)

add_library(Test2Lib STATIC src/Test2.cpp)
target_include_directories(Test2Lib PRIVATE include)
target_link_libraries(Test2Lib PUBLIC lib2)

add_library(Test3Lib STATIC src/Test3.cpp)
target_include_directories(Test3Lib PRIVATE include)
target_link_libraries(Test3Lib PUBLIC lib3)

# 单个测试目标(仅包含main函数,调用对应库的测试逻辑)
set(THIS UTest1)
string(TOUPPER DO_BUILD_${THIS} THIS_FLAG)
if (${THIS_FLAG})
  add_executable(${THIS} src/UTest1Main.cpp)
  target_link_libraries(${THIS} PUBLIC Test1Lib)
endif()

# UTestAll目标(统一main函数,调用所有测试库逻辑)
set(THIS UTestAll)
string(TOUPPER DO_BUILD_${THIS} THIS_FLAG)
if (${THIS_FLAG})
  add_executable(${THIS} src/UTestAllMain.cpp)
  target_link_libraries(${THIS} PUBLIC Test1Lib Test2Lib Test3Lib)
endif()

方案2:用CTest管理测试(更推荐)

无需手动编写UTestAll,利用CMake自带的CTest框架管理测试用例,通过ctest命令一键运行所有测试:

# 保留原有单个测试目标定义,添加CTest测试用例
if (DO_BUILD_UTEST1)
  add_test(NAME UTest1 COMMAND UTest1)
endif()

if (DO_BUILD_UTEST2)
  add_test(NAME UTest2 COMMAND UTest2)
endif()

if (DO_BUILD_UTEST3)
  add_test(NAME UTest3 COMMAND UTest3)
endif()

本地执行ctest即可运行所有启用的测试,每个源文件仅编译一次;还能通过ctest -R UTest1单独运行指定测试,灵活性远高于自定义UTestAll。


问题2解答

完全可以通过CMake选项控制目标的构建与执行:

1. 控制UTestAll的构建开关

你的代码已经通过DO_BUILD_UTESTALL控制UTestAll的构建,可在CMakeLists开头默认开启该选项:

option(DO_BUILD_UTESTALL "Build UTestAll target" ON)

Jenkins流水线构建时,通过CMake参数关闭它:

cmake .. -DDO_BUILD_UTESTALL=OFF

此时UTestAll不会被构建,自然不会执行。

2. 控制执行阶段

若需构建UTestAll但不执行,或仅运行单个测试,可在Jenkins执行步骤指定目标:

  • 仅运行单个测试:make UTest1 && ./UTest1
  • 跳过UTestAll:直接执行UTest1、UTest2、UTest3,不调用UTestAll可执行文件。

若使用CTest,还能通过ctest -R UTest[1-3]指定运行特定测试,或直接执行ctest运行所有启用的测试。


内容的提问来源于stack exchange,提问作者xyf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 14:21:00