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