3

要在 CMake 下注册测试,我们需要

enable_testing()

或者

include(CTest)

然后对于每个单独的测试(名称fooTest,可执行文件foo

add_executable(foo <foo_sources>)
add_test(fooTest foo)

然后可以使用命令运行测试ctest

此外,我们可以使用命令运行测试make check,只要我们添加一次

add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})

EXCLUDE_FROM_ALL对于每个测试,我们通过关键字和命令扩展上述内容add_dependencies

add_executable(foo EXCLUDE_FROM_ALL <foo_sources>)
add_test(fooTest foo)
add_dependencies(check foo)

make check理想情况下,这将使ctest. 至少有两个原因并非如此:

(1)make check是有缺陷的,因为它没有将选项传递给ctest[2]。特别是,ctest -j4将并行运行 4 个测试,而make -j4 check将在 target 上的一个线程中工作,而check其他三个线程将保持空闲状态。

(2)ctest是有缺陷的[3,4],因为所有测试都是在all目标下构建的,即与主应用程序一起构建。在某些情况下,这可能是期望的行为,但在其他情况下,应该可以将构建推迟到要运行测试为止。

这是否正确地概括了当前的事态?

有什么办法(吃蛋糕并拥有它)吗?

[1] https://cmake.org/Wiki/CMakeEmulateMakeCheck [2] http://comments.gmane.org/gmane.comp.programming.tools.cmake.user/47300 [3] CMake & CTest : make test 不'不构建测试 [4] http://public.kitware.com/Bug/view.php?id=8774

4

2 回答 2

2

首先,让我说一下ctestmake test这只是简单的命令行工具,用于简单的测试任务。如果您想要一个用于严肃测试的工具,请使用 Cdash、Buildbot、Jenkins 或其他任何工具。

关于 CTest 的缺陷:有意调用 CTest 并没有构建测试。在以下几种情况下这是一个坏主意:

  • 编译测试可能会占用更多资源,然后运行测试本身。对于内存消耗、对硬盘的读/写或编译时间而言,这可能是正确的。所以并行编译和链接可能不好,但并行执行测试可能是有益的。
  • 如何处理编译或链接失败?报告失败?报告不编译?继续编译其他测试还是立即中止?

Autotools 以您想要的方式进行操作,人们已经习惯了。但是为什么它应该是一个单元呢?为什么没有两个命令?将两个任务混合在一起,让有特殊需求的项目更难完成有什么好处?

我得出的结论是,创建一个目标build-tests或类似的目标,并遵循 CMake 开发人员做出的决定,将构建测试和执行测试解耦。然后我可以决定是否需要并行构建,如何处理编译失败(例如,传递-k给 make)等等。
唯一的缺点是,这个目标只存在于顶级目录中,不能在子目录中使用。
让 CMake 内置这样一个目标将是一个很好的功能请求。对 SO 大喊大叫没有好处。

于 2016-06-06T08:44:10.690 回答
1

CTest根本没有缺陷,但是您使用 CMake 和 CTest 的方式似乎“有缺陷”。命令行界面 (CLI) 工具ctest的调用通常与 CMake 构建目标的调用无关(除了 target test)。

在我看来,不应使用CMake Wikicheck中描述的自定义目标解决方案,因为它会更改 CMake 的默认行为并且不可配置。

相反,应使用以下使用内置选项的BUILD_TESTING方法:

include(CTest)
if(BUILD_TESTING)
  find_package(GTest MODULE REQUIRED)
  add_executable(example_test example_test.cpp)
  target_link_libraries(
    example_test
    PRIVATE
      GTest::GTest
      GTest::Main
  )
  add_test(NAME example_test COMMAND example_test)
endif()

include(CTest)option BUILD_TESTING中定义,允许控制是否构建项目的所有测试。

引用官方文档

enable_testing()只有当命令被调用时,CMake 才会生成测试。该模块在选项CTest为时自动调用命令。BUILD_TESTINGON

以上可以在 CLI 上使用,如下所示:

  1. 创建测试(默认):

    cmake -Hexample-testing -B_builds/example-testing/release -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
    cmake --build _builds/example-testing/release --config Release
    

    在这种情况下,命令cd _builds/example-testing/releasectest/cmake --build . --target test构建运行测试。

  2. 不要创建测试,设置-DBUILD_TESTING=OFF

    cmake -Hexample-testing -B_builds/example-testing/release-no-tests -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF
    cmake --build _builds/example-testing/release-no-tests --config Release
    

    在这种情况下,命令cd _builds/example-testing/release-no-testsctest不会运行任何测试,因为没有构建任何测试。该命令cmake --build . --target test 失败,因为它尚未在 CMake 的配置阶段创建。

我们在这里只是触及表面。请参阅ctest --help,例如,有很多--build-<...>选项可以更好地控制测试/构建,尽管我对此没有任何经验。

我强烈建议阅读以下内容:

如果您真的想启用测试构建,但通过默认情况下不调用的单独目标并且不是通过 CTest 而是直接运行测试,您可以执行以下操作:

include(CTest)
if(BUILD_TESTING)
  find_package(GTest MODULE REQUIRED)
  option(
    BUILD_TESTING_EXCLUDE_FROM_ALL
    "Do not build the testing tree together with the default build target."
    OFF
  )

  if(BUILD_TESTING_EXCLUDE_FROM_ALL)
    set(add_executable_args_for_test EXCLUDE_FROM_ALL)
  endif()

  # The "build_test" target is used to build all test executables.
  add_custom_target(
    build_test
    # Workaround for printing the COMMENT, it does not work without a NOOP
    # COMMAND.
    COMMAND ${CMAKE_COMMAND} -E echo
    COMMENT "Building tests..."
    VERBATIM
  )
  add_executable(example_test ${add_executable_args_for_test} example_test.cpp)
  target_link_libraries(
    example_test
    PRIVATE
      GTest::GTest
      GTest::Main
  )
  add_test(NAME example_test COMMAND example_test)
  add_dependencies(build_test example_test)

  # The "check" target is used to build AND run all test executables.
  add_custom_target(
    check
    # Either invoke the test(s) indirectly via "CTest" (commented) or directly.
#   COMMAND ${CMAKE_CTEST_COMMAND}
    COMMAND example_test
    COMMENT "Building and running test..."
    VERBATIM
  )
  # Alternative to the COMMAND in the add_custom_target. Leads to the same
  # behavior as calling "CTest" directly.
#  add_custom_command(
#    TARGET check
#    COMMAND ${CMAKE_COMMAND} ARGS --build ${CMAKE_BINARY_DIR} --target test
#    VERBATIM
#  )
   add_dependencies(check build_test)
endif()
  • 请注意,上面的代码不是test为了运行测试而调用 CTest 或目标,而是直接调用测试。
  • 请阅读与问题中描述的方法类似的使用 CTest 的替代方法的注释和注释代码。
  • 增强上述代码以支持多个测试可执行文件很容易。

恕我直言,Kitware 应该删除整个 CMake Wiki,因为 Wiki 几乎只包含 CMake 版本 < 3.0 的过时信息。其中的大多数信息都不能被视为Modern CMake

于 2017-02-14T20:11:50.897 回答