CMake Test编写

CMake Test

cmake对任何编程语言进行测试

自定义CMake的Test

项目目录如下

.
├── CMakeLists.txt
├── main.cpp
├── sum_integers.cpp
├── sum_integers.hpp
├── test.cpp
├── test.py
└── test.sh
  • sum_integers为项目源文件。
  • main为从命令行获取测试数据并调用sum_integers的功能,并返回计算结果。
  • test为在test文件中设定测试数据,并调用相应的程序将测试数据传输给main的可执行文件。由main可执行程序计算,并返回计算结果。test获取计算结果,根据test文件中的设定,判断测试成功与否。

cmake中的test编写

  • enable_testing() 启用test功能,测试该CMakeList.txt所在目录及其所有子文件夹。
  • add_test() 定义一个新测试,并设置测试名称和运行命令

例如:

add_test(
    NAME cpp_test
    COMMAND $<TARGET_FILE:cpp_test>
)
  • 创建了一个名为cpp_test的测试项
  • COMMAN表示执行对应的命令
  • $<TARGET_FILE:cpp_test> 为生成器表达式。构建时,cmake会将名cpp_test这个可执行文件的完整路径,替换为该生成器表达式。并执行。以便可以不显示的指定可执行程序的位置和名称,而且不同系统的可执行文件名可能不同,不好移植

再例如:

add_test(
  NAME python_test_short
  COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py --short --executable $<TARGET_FILE:sum_up>
  )

构建一个名为python_test_short的测试项。调用python解释器,指定test.py的选项参数为–short, --executable , $<TARGET_FILE:sum_up>即为test文件所需要使用到的可执行程序(为main程序)。test.py产生调用main程序使用指定的测试数据进行测试,并获取测试结果,并返回测试成功与否。

编译完后,执行ctest命令即可进行测试。

  • 添加--return-failed执行之前失败的测试
  • –output-on-failure 将测试程序生成的内容打印到屏幕上
  • -v 将启用测试的详细输出
  • -vv 将启用更详细的输出

cmake还将为生成器创建目标。

  • Unix Makefile生成器,通过make test测试
  • Ninja生成器,通过ninja test测试
指定测试的工作目录

例如:

add_test(
  NAME python_test_long
  COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py --executable $<TARGET_FILE:sum_up>
  )

可以改写为如下,指定工作目录。

add_test(
  NAME python_test_long
  COMMAND ${PYTHON_EXECUTABLE} test.py --executable $<TARGET_FILE:sum_up>
  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
  )
按名称组织相关测试

测试名称添加/即可

add_test(
  NAME python/long
  COMMAND ${PYTHON_EXECUTABLE} test.py --executable $<TARGET_FILE:sum_up>
  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
  )
为测试脚本设置环境变量
set_tests_properties(python_test
  PROPERTIES
    ENVIRONMENT
      ACCOUNT_MODULE_PATH=${CMAKE_CURRENT_SOURCE_DIR}
      ACCOUNT_HEADER_FILE=${CMAKE_CURRENT_SOURCE_DIR}/account/account.h
      ACCOUNT_LIBRARY_FILE=$<TARGET_FILE:account>
  )

也可以通过CMAKE_COMMAND调用CMake来预先设置环境变量。

add_test(
  NAME
      python_test
  COMMAND
    ${CMAKE_COMMAND} -E env
    ACCOUNT_MODULE_PATH=${CMAKE_CURRENT_SOURCE_DIR}
    ACCOUNT_HEADER_FILE=${CMAKE_CURRENT_SOURCE_DIR}/account/account.h
    ACCOUNT_LIBRARY_FILE=$<TARGET_FILE:account>
    ${PYTHON_EXECUTABLE}
    ${CMAKE_CURRENT_SOURCE_DIR}/account/test.py
  )

Catch2 Test

Catch2是一个C++的测试框架。

Catch2的安装

git clone -b v3.3.2 https://github.com/catchorg/Catch2.git

cd Catch2
mkdir -p build&&cd build
cmake ..
make && make install 

Catch2在cmake中的使用

Catch2 CMake

  1. 找到Catch2库
find_package(Catch2 3 REQUIRED)
  1. 测试文件链接到Catch2
target_link_libraries(target_name 
            PRIVATE 
                Catch2::Catch2WithMain
)
  1. 开启测试
enable_testing()
  1. 添加测试项
add_test(
    NAME catch2_test
    COMMAND $<TARGET_FILE:target_name> --success
)

执行测试

ctest -v //测试时输出详细信息
或
make test //如果构建器是unix makefile

也可以测试二进制文件,--success是catch2的选项

./target_name --success

使用-h可以查看Catch2提供的选项

./target_name --help

googleTest

Google Test框架不仅仅是一个头文件,也是一个库,包含两个需要构建和链接的文件(gtest gtest_main gmock gmock_main)。

使用FetchContent来获取第三方库,并链接。(不用安装,更加轻量级)。

获取googletest

include(FetchContent)
FetchContent_Declare(
    googletest
    GIT_REPOSITORY https://github.com/google/googletest.git
    GIT_TAG v1.13.0
)
#使gtest可用
FetchContent_MakeAvailable(googletest)

googletest在cmake中的使用

测试项链接到googletest

target_link_libraries(test_target
  PRIVATE
    gtest_main
)

启动测试项

enable_testing()
add_test(
  NAME google_test
  COMMAND $<TARGET_FILE:test_target>
)

Boost Test

Boost是c++社区非常流行的测试框架。

安装Boost

apt-get  install libboost-all-dev

查找boost库并链接

find_package(Boost 1.74 REQUIRED COMPONENTS unit_test_framework)

target_link_libraries(
    test_target
    PRIVATE
        Boost::unit_test_framework
)

给测试文件添加main函数的定义

target_compile_definitions(
    test_target
    PRIVATE
        BOOST_TEST_DYN_LINK
)

启用测试项

enable_testing()
add_test(
  NAME boost_test
  COMMAND $<TARGET_FILE:test_target>
)

测试

make test //如果构建器为unix makefile
或
ctest -vv

使用动态分析检测内存缺陷

内存缺陷:写入或读取越界,或者内存泄漏(已分配但从未释放的内存),会产生难以跟踪的bug

Valgrind 是一个通用的工具,用来检测内存缺陷和内存泄漏。

valgrind安装

apt-get install valgrind

定义测试目标和MEMORYCHECK_COMMAND

# 查找valgrind,并将MEMORYCHECK_COMMAND设置为其绝对路径
find_program(MEMORYCHECK_COMMAND NAMES valgrind)
# 将相关参数传递给valgrind
set(MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full")

添加内存检测到ctest中

#显示添加CTest模块启用memcheck
include(CTest)

开启测试

enable_testing()
add_test(
  NAME test_target_name
  COMMAND $<TARGET_FILE:test_target>
  )

检查内存缺陷

ctest -T memcheck

预期测试失败的测试项

在某些情况,我们就是测试希望测试失败的测试项。即指定测试失败的项为成功。

  • 当使用测试框架(gtest boost catch2)时,可以通过测试框架进行设置。
  • 当不使用框架时,设定该测试项的选项即可。

设置测试项失败为成功

# 将属性WILL_FAIL设置为true,将转换成功与失败
set_tests_properties(test_target PROPERTIES WILL_FAIL true)

如果需要更大的灵活性,可以将测试属性PASS_REGULAR_EXPRESSIONFAIL_REGULAR_EXPRESSIONset_tests_properties组合使用。如果设置了这些参数,测试输出将根据参数给出的正则表达式列表进行检查,如果匹配了正则表达式,测试将通过或失败。

设置超时测试运行时间过长的测试

设置超时来终止耗时过长的测试。

# 超过10s即测试失败
set_tests_properties(test_target_name PROPERTIES TIMEOUT 10)

并行测试

使用多核来减少测试时间。
执行测试时,可以使用以下命令,利用多核进行测试。

ctest --parallel N

或者在CMakeLists.txt中将CTEST_PARALLEL_LEVEL设置为所需要的级别即可。
例如:

set(CTEST_PARALLEL_LEVEL 4)

并行测试须知

  • 不并行测试时,测试顺序执行
  • 当第一次并行测试时,测试顺序执行
  • 当非第一次并行测试时,测试从耗时最长的测试项开始进行
  • cmake会记录各个对应测试项的测试时间,在非第一次测试时,会从耗时最长的开始执行。
  • 可以通过set_tests_properties来预先评估测试时间,以便cmake自动从最长的测试项开始测试。(即使时首次测试)

例如:

set_tests_properties(
    test_target
    PROPERTIES COST 2.5
)

测试子集

有时不需要运行所有测试项,可以使用测试子集。

  • 通过添加测试项的标签,从而可以只测试部分项。
ctest --parallel 4 -L myLabel
  • 也可以通过名称只测试部分
ctest --parallel 4 -R testName
  • 当在CMakeLists.txt中添加测试项后,cmake会自动为每个测试项设置编号,从1开始。可以指定测试项编号进行测试
ctest --parallel 4 -I 3,5

为测试项添加测试标签

set_test_properties(
  test_target
  PROPERTIES
    LABELS "myLabel"
)

使用测试固件

有时在测试前需要进行某些操作,在测试完成后需要执行某些操作。这些都可以通过测试固件绑定测试项完成。
例如:

add_test(
  NAME setup
  COMMAND ${PYTHON_EXECUTABLE} setup.py
  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test/
  )
set_tests_properties(
  setup
  PROPERTIES
      FIXTURES_SETUP my-fixture
  )
add_test(
  NAME feature-a
  COMMAND ${PYTHON_EXECUTABLE} feature-a.py
  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test/

)
add_test(
  NAME feature-b
  COMMAND ${PYTHON_EXECUTABLE} feature-b.py
  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test/

)
set_tests_properties(
  feature-a
  feature-b
  PROPERTIES
      FIXTURES_REQUIRED my-fixture
  )
add_test(
  NAME cleanup
  COMMAND ${PYTHON_EXECUTABLE} cleanup.py
  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test/
)
set_tests_properties(
  cleanup
  PROPERTIES
      FIXTURES_CLEANUP my-fixture
  )
  • setup为测试时的前置操作,cleanup为测试后所需要进行的操作。
  • 定义了一个my-fixture的测试固件,该测试固件设定了 FIXTURES_SETUPFIXTURES_CLEANUP属性。
  • 将测试固件绑定到feature-a和feature-b,并设定为必须(FIXTURES_REQUIRED)

上述例子,在测试执行前会执行setup操作,测试完成后会执行cleanup操作。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值