GoogleTest

GoogleTest 和 GoogleMock 是非常经典的选择;不过就我个人经验而言,我会推荐你使用 Catch2,因为 GoogleTest 十分遵循谷歌的发展理念;它假定用户总是想使用最新的技术,因此会很快的抛弃旧的编译器(不对其适配)等等。添加 GoogleMock 也常常令人头疼,并且你需要使用 GoogleMock 来获得匹配器(matchers),这在 Catch2 是一个默认特性,而不需要手动添加(但 docstest 没有这个特性)。

子模块(Submodule)的方式(首选)

当使用这种方式,只需要将 GoogleTest 设定(checkout) 为一个子模块:1

  1. git submodule add --branch=release-1.8.0 ../../google/googletest.git extern/googletest

然后,在你的主 CMakeLists.txt 中:

  1. option(PACKAGE_TESTS "Build the tests" ON)
  2. if(PACKAGE_TESTS)
  3. enable_testing()
  4. include(GoogleTest)
  5. add_subdirectory(tests)
  6. endif()

我推荐你使用一些像 PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME 来设置 PACKAGE_TEST 选项的默认值,因为这样只会在项目为主项目时才构建测试单元。

像之前提到的,你必须在你的主 CMakeLists.txt 文件中调用 enable_testing() 函数。 现在,在你的 tests 目录中:

  1. add_subdirectory("${PROJECT_SOURCE_DIR}/extern/googletest" "extern/googletest")

如果你在你的主 CMakeLists.txt 中调用它,你可以使用普通的 add_subdirectory;这里因为我们是从子目录中调用的,所以我们需要一个额外的路径选项来更正构建路径。

下面的代码是可选的,它可以让你的 CACHE 更干净:

  1. mark_as_advanced(
  2. BUILD_GMOCK BUILD_GTEST BUILD_SHARED_LIBS
  3. gmock_build_tests gtest_build_samples gtest_build_tests
  4. gtest_disable_pthreads gtest_force_shared_crt gtest_hide_internal_symbols
  5. )

If you are interested in keeping IDEs that support folders clean, I would also add these lines:

  1. set_target_properties(gtest PROPERTIES FOLDER extern)
  2. set_target_properties(gtest_main PROPERTIES FOLDER extern)
  3. set_target_properties(gmock PROPERTIES FOLDER extern)
  4. set_target_properties(gmock_main PROPERTIES FOLDER extern)

然后,为了增加一个测试,推荐使用下面的宏:

  1. macro(package_add_test TESTNAME)
  2. # create an exectuable in which the tests will be stored
  3. add_executable(${TESTNAME} ${ARGN})
  4. # link the Google test infrastructure, mocking library, and a default main fuction to
  5. # the test executable. Remove g_test_main if writing your own main function.
  6. target_link_libraries(${TESTNAME} gtest gmock gtest_main)
  7. # gtest_discover_tests replaces gtest_add_tests,
  8. # see https://cmake.org/cmake/help/v3.10/module/GoogleTest.html for more options to pass to it
  9. gtest_discover_tests(${TESTNAME}
  10. # set a working directory so your project root so that you can find test data via paths relative to the project root
  11. WORKING_DIRECTORY ${PROJECT_DIR}
  12. PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${PROJECT_DIR}"
  13. )
  14. set_target_properties(${TESTNAME} PROPERTIES FOLDER tests)
  15. endmacro()
  16. package_add_test(test1 test1.cpp)

这可以简单、快速的添加测试单元。你可以随意更改来满足你的需求。如果你之前没有了解过 ARGNARGN 是显式声明的参数外的所有参数。如 package_add_test(test1 test1.cpp a b c)ARGN 包含除 test1test1.cpp 外的所有参数。

可以更改宏来满足你的要求。例如,如果你需要链接不同的库来进行不同的测试,你可以这么写:

  1. macro(package_add_test_with_libraries TESTNAME FILES LIBRARIES TEST_WORKING_DIRECTORY)
  2. add_executable(${TESTNAME} ${FILES})
  3. target_link_libraries(${TESTNAME} gtest gmock gtest_main ${LIBRARIES})
  4. gtest_discover_tests(${TESTNAME}
  5. WORKING_DIRECTORY ${TEST_WORKING_DIRECTORY}
  6. PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}"
  7. )
  8. set_target_properties(${TESTNAME} PROPERTIES FOLDER tests)
  9. endmacro()
  10. package_add_test_with_libraries(test1 test1.cpp lib_to_test "${PROJECT_DIR}/european-test-data/")

下载的方式

你可以通过 CMake 的 include 指令使用使用我在 CMake helper repository 中的下载器,

这是一个 GoogleTest 的下载器,基于优秀的 DownloadProject 工具。为每个项目下载一个副本是使用 GoogleTest 的推荐方式(so much so, in fact, that they have disabled the automatic CMake install target), so this respects that design decision. 这个方式在项目配置时下载 GoogleTest,所以 IDEs 可以正确的找到这些库。这样使用起来很简单:

  1. cmake_minimum_required(VERSION 3.10)
  2. project(MyProject CXX)
  3. list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
  4. enable_testing() # Must be in main file
  5. include(AddGoogleTest) # Could be in /tests/CMakeLists.txt
  6. add_executable(SimpleTest SimpleTest.cu)
  7. add_gtest(SimpleTest)

提示:add_gtest 只是一个添加 gtestgmock 以及 gtest_main 的宏,然后运行 add_test 来创建一个具有相同名字的测试单元

  1. target_link_libraries(SimpleTest gtest gmock gtest_main)
  2. add_test(SimpleTest SimpleTest)

FetchContent: CMake 3.11

这个例子是用 FetchContent 来添加 GoogleTest:

  1. include(FetchContent)
  2. FetchContent_Declare(
  3. googletest
  4. GIT_REPOSITORY https://github.com/google/googletest.git
  5. GIT_TAG release-1.8.0
  6. )
  7. FetchContent_GetProperties(googletest)
  8. if(NOT googletest_POPULATED)
  9. FetchContent_Populate(googletest)
  10. add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
  11. endif()
  1. 在这里我假设你在 Github 仓库中使用 googletest,然后使用的是 googletest 的相对路径。