如何为scikit-build的pybind模块集成C++单元测试
适配scikit-build的Python模块添加C++单元测试(Google Test)配置方案
问题背景
我基于官方pybind scikit-build示例开发Python模块,目前已有放在tests目录下、通过pytest运行的Python单元测试。由于模块中存在未暴露给Python的C内部库,希望添加C单元测试验证这些逻辑,需要让CMake配置同时适配pyproject.toml调用的pip install .安装流程,以及直接用cmake命令构建的场景,同时不想额外复杂化pybind11的依赖管理。
核心思路
无需单独管理pybind11依赖,scikit-build会自动处理;通过CMake选项控制C++测试的构建开关:默认pip install .时不构建测试,仅在手动调用cmake并开启测试选项时才构建测试目标。
具体配置步骤
1. 修改CMakeLists.txt
在现有配置中添加Google Test集成逻辑,同时保留原有Python模块构建流程:
# 1. 自动拉取Google Test(无需手动安装) include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG release-1.12.1 # 指定稳定版本 ) # 避免gtest覆盖项目编译配置 set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) # 2. 添加测试构建开关,默认关闭(适配pip install流程) option(BUILD_CPP_TESTS "Build C++ unit tests" OFF) # 3. 原有Python模块构建逻辑保持不变 find_package(pybind11 REQUIRED) pybind11_add_module(your_module src/your_module.cpp) # 链接内部C++库到Python模块 target_link_libraries(your_module PRIVATE your_internal_lib) # 4. 开启测试开关时,构建C++测试目标 if(BUILD_CPP_TESTS) # 创建测试可执行文件 add_executable(cpp_tests tests/cpp/test_internal_lib.cpp) # 链接依赖:内部库+gtest target_link_libraries(cpp_tests PRIVATE your_internal_lib GTest::gtest_main) # 注册测试到CTest,支持用ctest批量运行 include(GoogleTest) gtest_discover_tests(cpp_tests) endif()
2. 适配pyproject.toml
无需额外修改,pip install .会默认使用CMake的BUILD_CPP_TESTS=OFF选项,不会触发C++测试构建,不影响正常安装流程。
3. 手动构建并运行C++测试
直接通过cmake命令开启测试开关即可:
# 创建构建目录 mkdir build && cd build # 配置CMake并开启C++测试 cmake .. -DBUILD_CPP_TESTS=ON # 构建测试 cmake --build . # 运行测试 ctest --output-on-failure
4. GitHub Action集成C++测试
在CI脚本中添加单独步骤执行测试:
jobs: cpp-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up CMake uses: jwlawson/actions-setup-cmake@v1.13.0 with: cmake-version: '3.22.x' - name: Build and run C++ tests run: | mkdir build && cd build cmake .. -DBUILD_CPP_TESTS=ON cmake --build . ctest --output-on-failure
关键细节说明
- pybind11依赖兼容:
pip install .时scikit-build会自动处理pybind11的安装与查找;手动cmake时,find_package(pybind11 REQUIRED)会优先查找系统已安装版本,若想完全脱离系统依赖,可添加以下代码自动拉取:if(NOT DEFINED pybind11_DIR) FetchContent_Declare( pybind11 GIT_REPOSITORY https://github.com/pybind/pybind11.git GIT_TAG v2.10.4 # 指定对应版本 ) FetchContent_MakeAvailable(pybind11) endif() - 测试隔离:C++测试与Python测试完全独立,不会互相干扰,正常安装流程不会包含测试代码。
内容的提问来源于stack exchange,提问作者sodiumnitrate
相关产品推荐
相关产品推荐

