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"。

相关推荐
不会代码的小猴6 小时前
21. 泛型编程上
开发语言·c++·笔记·算法
青瓦梦滋7 小时前
传输层UDP/TCP协议
linux·网络·c++·网络协议·tcp/ip·udp
一只旭宝7 小时前
细讲C加加【9】C++ std::function与std::bind详解|仿函数、绑定器、类成员绑定、占位符、成员偏移指针
开发语言·c++·算法
Lhan.zzZ9 小时前
在 Visual Studio 2022 中打造可扩展的动态链接库模块:从零搭建到原理解析
开发语言·c++·visual studio
zh路西法11 小时前
【3D SLAM源码解读系列】(二)Small_gicp——5 个积木搭出最优点云配准
c++·pcl·icp·fastgicp·smallgicp·gicp
fpcc13 小时前
ubuntu26环境下的开发环境安装处理
c++·并行编程
charlie11451419114 小时前
Cinux · 第一次跳进 Ring 3:用户态与特权隔离
开发语言·c++·操作系统·开源项目
别动我齐刘海15 小时前
机器学习基础2——C++、OpenCV、点云、Open3D
c++·人工智能·opencv·机器学习·计算机视觉·机器人·ros2
躺不平的理查德15 小时前
Windows C++ 第三方库使用流程备忘录--OpenCV
开发语言·c++
余额瞒着我当琳15 小时前
C++STL容器string--迭代器,string的接口,string的遍历,访问方式
c++