GoogleTest 使用指南 | 单元覆盖率分析

GoogleTest 使用指南 | 单元覆盖率分析

  • [GoogleTest 使用指南 | 单元测试覆盖率分析](#GoogleTest 使用指南 | 单元测试覆盖率分析)

GoogleTest 使用指南 | 单元测试覆盖率分析

除了查看测试通过与否,分析测试覆盖率也是提升代码质量的重要手段。覆盖率分析工具可以帮助识别未被测试的代码路径。

以下演示的是 Apple 芯片的 MacBook 上安装 GCC 版本 lcov 进行覆盖率分析。

安装 GCC:

bash 复制代码
brew install gcc

安装 GCC 编译覆盖率版本的 lcov:

bash 复制代码
brew install gcc lcov

查看 GCC 版本:

bash 复制代码
➜  googletest-example git:(master) ls /opt/homebrew/bin/gcc-*
/opt/homebrew/bin/gcc-15        /opt/homebrew/bin/gcc-ar-15     /opt/homebrew/bin/gcc-nm-15     /opt/homebrew/bin/gcc-ranlib-15

➜  googletest-example git:(master) ls /opt/homebrew/bin/g++-*
/opt/homebrew/bin/g++-15

配置覆盖率构建目录:

bash 复制代码
cmake -S . -B build-coverage \
    -DCMAKE_BUILD_TYPE=Debug \
    -DCMAKE_C_COMPILER="$(brew --prefix)/bin/gcc-15" \
    -DCMAKE_CXX_COMPILER="$(brew --prefix)/bin/g++-15" \
    -DCMAKE_C_FLAGS="--coverage -O0 -g" \
    -DCMAKE_CXX_FLAGS="--coverage -O0 -g" \
    -DCMAKE_EXE_LINKER_FLAGS="--coverage"

输出:

复制代码
Test project /Users/xiye/CppProjects/googletest-example/build-coverage
      Start  1: test_main
 1/14 Test  #1: test_main ........................   Passed    0.60 sec
      Start  2: test_max
 2/14 Test  #2: test_max .........................   Passed    0.35 sec
      Start  3: test_min
 3/14 Test  #3: test_min .........................   Passed    0.36 sec
      Start  4: test_prime
 4/14 Test  #4: test_prime .......................   Passed    0.36 sec
      Start  5: test_suite
 5/14 Test  #5: test_suite .......................   Passed    0.36 sec
      Start  6: test_calculator
 6/14 Test  #6: test_calculator ..................   Passed    0.37 sec
      Start  7: test_container
 7/14 Test  #7: test_container ...................   Passed    0.34 sec
      Start  8: test_numeric
 8/14 Test  #8: test_numeric .....................   Passed    0.41 sec
      Start  9: test_queue
 9/14 Test  #9: test_queue .......................   Passed    0.35 sec
      Start 10: test_bank_vault
10/14 Test #10: test_bank_vault ..................   Passed    0.34 sec
      Start 11: test_utility
11/14 Test #11: test_utility .....................   Passed    0.35 sec
      Start 12: test_database
12/14 Test #12: test_database ....................   Passed    0.36 sec
      Start 13: test_add_param
13/14 Test #13: test_add_param ...................   Passed    0.36 sec
      Start 14: test_network_client
14/14 Test #14: test_network_client ..............   Passed    0.37 sec

100% tests passed, 0 tests failed out of 14

Total Test time (real) =   5.32 sec

构建并运行测试:

bash 复制代码
cmake --build build-coverage
lcov --directory build-coverage --zerocounters
ctest --test-dir build-coverage --output-on-failure

收集覆盖率:

bash 复制代码
lcov --capture \
    --directory build-coverage \
    --gcov-tool /opt/homebrew/bin/gcov-15 \
    --ignore-errors inconsistent \
    --output-file build-coverage/coverage.info

过滤第三方库、测试代码、构建目录:

bash 复制代码
lcov --remove build-coverage/coverage.info \
    "*/_deps/*" \
    "*/tests/*" \
    "/Applications/*" \
    "/Library/*" \
    "/opt/homebrew/*" \
    --gcov-tool /opt/homebrew/bin/gcov-15 \
    --ignore-errors unused \
    --output-file build-coverage/coverage.filtered.info

生成 HTML:

bash 复制代码
genhtml build-coverage/coverage.filtered.info \
    --output-directory build-coverage/coverage-report

打开报告:

bash 复制代码
open build-coverage/coverage-report/index.html

结果:

打开单个文件,可以查看每一行的覆盖情况:

可以在 CMakeLists.txt 中添加覆盖率编译选项,由 ENABLE_COVERAGE 开关控制。

txt 复制代码
option(ENABLE_COVERAGE "Enable coverage flags" OFF)

function(enable_coverage target)
	if(ENABLE_COVERAGE)
		target_compile_options(${target} PRIVATE --coverage -O0 -g)
		target_link_options(${target} PRIVATE --coverage)
	endif()
endfunction()

然后在每个目标创建后调用它,例如你的项目里可以这样:

txt 复制代码
  add_library(example_lib
      src/calculator.cpp
      src/max.cpp
  )
  target_include_directories(example_lib PUBLIC
      ${CMAKE_CURRENT_SOURCE_DIR}/include
  )
  enable_coverage(example_lib)

  add_executable(main src/main.cpp)
  target_link_libraries(main PRIVATE example_lib)
  enable_coverage(main)

你的测试函数也可以改成:

txt 复制代码
  function(add_gtest_target target)
      add_executable(${target} ${ARGN})
      target_link_libraries(${target} PRIVATE example_lib gtest_main)
      enable_coverage(${target})
      add_test(NAME ${target} COMMAND ${target})
  endfunction()

单独写的测试目标也要加:

txt 复制代码
  add_executable(test_network_client tests/test_network_client.cpp)
  target_link_libraries(test_network_client PRIVATE example_lib gmock_main)
  enable_coverage(test_network_client)
  add_test(NAME test_network_client COMMAND test_network_client)

之后用 GCC 配置覆盖率构建:

bash 复制代码
  cmake -S . -B build-coverage \
    -DCMAKE_BUILD_TYPE=Debug \
    -DCMAKE_C_COMPILER=/opt/homebrew/bin/gcc-15 \
    -DCMAKE_CXX_COMPILER=/opt/homebrew/bin/g++-15 \
    -DENABLE_COVERAGE=ON

再构建和测试:

bash 复制代码
  cmake --build build-coverage
  ctest --test-dir build-coverage --output-on-failure

这样覆盖率选项就由 CMake 管理,不需要每次手动传 CMAKE_CXX_FLAGS="--coverage -O0 -g"。

相关推荐
叶之香1 小时前
一次 Kingston U 盘重定向中获取 Device Descriptor 超时问题排查
c++·windows·visual studio
霸道流氓气质1 小时前
Mockito 单元测试从入门到实战:Java Service 层测试完全指南
单元测试·mockito
王老师青少年编程1 小时前
csp信奥赛C++高频考点专项训练之前缀和&差分 --【一维前缀和】:“非常男女”计划
c++·前缀和·csp·高频考点·信奥赛·“非常男女”计划
故事和你911 小时前
洛谷-【图论2-4】连通性问题2
开发语言·数据结构·c++·算法·动态规划·图论
Brilliantwxx1 小时前
【C++】 二叉搜索树
开发语言·c++·算法
于小猿Sup12 小时前
VMware在Ubuntu22.04驱动Livox Mid360s
linux·c++·嵌入式硬件·自动驾驶
小小编程路14 小时前
C++ 多线程与并发
java·jvm·c++
程序leo源15 小时前
Qt窗口详解
开发语言·数据库·c++·qt·青少年编程·c#
zh_xuan16 小时前
解决VS Code 控制台中文乱码
c++·vscode·乱码