CMake和CTest:make测试不会建立测试


89

我正在CMake中尝试CTest,以便使用来自动运行某些测试 make testtarget。问题在于CMake不能“理解”我愿意运行的测试,因为它是项目的一部分,因此必须进行构建。

因此,我正在寻找一种明确指定此依赖性的方法。

Answers:


79

可以说这是CMake的一个错误(以前在这里跟踪),它无法立即使用。解决方法是执行以下操作:

add_test(TestName ExeName)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}
                  DEPENDS ExeName)

然后可以运行make check,它将编译并运行测试。如果您有多个测试,则必须DEPENDS exe1 exe2 exe3 ...在上一行中使用。


1
所以我想“ make test”目标将保持未使用状态,因为您似乎必须在add_custom_target命令中选择其他目标名称?
claf

是的 “ make test”和“ make check”之间的唯一区别是前者首先显示“正在运行测试...”,并且不检查任何构建依赖项。
09年

2
@rq-但是我如何使用多个项目(当一个CMakeLists.txt是另一个项目的子项目时)做到这一点,因此每个项目都将定义check目标并且它们可能会发生冲突
Artyom 2010年

2
@Artyom-在这种情况下,最好使用等效的“全部测试”。实际上,这就是我要做的。
richq 2010年

4
实际上,有些人认为它可以作为cmake的一项功能(不是bug),您可以运行“ make test”并仅按原样运行测试,而无需先进行任何重新构建……
DLRdave

55

实际上有一种使用方法make test。您需要将测试可执行文件的构建定义为测试之一,然后在测试之间添加依赖项。那是:

ADD_TEST(ctest_build_test_code
         "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target test_code)
ADD_TEST(ctest_run_test_code test_code)
SET_TESTS_PROPERTIES(ctest_run_test_code
                     PROPERTIES DEPENDS ctest_build_test_code)

11
这是唯一可以扩大规模并且不会强迫您仅为了运行测试而构建“全部”目标的目标。可能的缺点:二进制文件上的生成错误的详细信息仅显示在生成的LastTest.log文件中,而不显示在stdout / stderr上
Dave Abrahams

2
好答案!您应该将配置添加到构建目标。否则,不可能在所有配置中都运行测试。add_test(NAME“ $ {ARGV0} _BUILD” COMMAND“ $ {CMAKE_COMMAND}” --build $ {CMAKE_BINARY_DIR} --target $ {target}“ --config”“ $ <CONFIG>”)
丹尼尔(Daniel

1
这用一堆假冒的测试堵塞了测试记者。

如果您使用的是CMake> = 3.7,建议的方法是使用灯具。请参阅下面的答案
约翰·弗里曼

13

我使用richq的答案的变体。在顶层CMakeLists.txt,我添加了一个自定义目标build_and_test,用于构建和运行所有测试:

find_package(GTest)
if (GTEST_FOUND)
    enable_testing()
    add_custom_target(build_and_test ${CMAKE_CTEST_COMMAND} -V)
    add_subdirectory(test)
endif()

在下的各个子项目CMakeLists.txt文件中test/,我将每个测试可执行文件添加为以下项的依赖项build_and_test

include_directories(${CMAKE_SOURCE_DIR}/src/proj1)
include_directories(${GTEST_INCLUDE_DIRS})
add_executable(proj1_test proj1_test.cpp)
target_link_libraries(proj1_test ${GTEST_BOTH_LIBRARIES} pthread)
add_test(proj1_test proj1_test)
add_dependencies(build_and_test proj1_test)

使用这种方法,我只需要make build_and_test代替make test(或make all test),它的好处是仅构建测试代码(及其依赖项)。可惜我不能使用目标名称test。就我而言,这还不错,因为我有一个顶层脚本,该脚本通过调用cmake然后进行树外调试和发行(和交叉编译)make,并将其转换testbuild_and_test

显然,不需要GTest东西。我只是碰巧使用/喜欢Google Test,并想与CMake / CTest分享使用它的完整示例。恕我直言,这种方法还具有允许我使用的好处ctest -V,它可以在测试运行时显示Google Test的输出:

1: Running main() from gtest_main.cc
1: [==========] Running 1 test from 1 test case.
1: [----------] Global test environment set-up.
1: [----------] 1 test from proj1
1: [ RUN      ] proj1.dummy
1: [       OK ] proj1.dummy (0 ms)
1: [----------] 1 test from proj1 (1 ms total)
1:
1: [----------] Global test environment tear-down
1: [==========] 1 test from 1 test case ran. (1 ms total)
1: [  PASSED  ] 1 test.
1/2 Test #1: proj1_test .......................   Passed    0.03 sec

在此示例中,是否有一种方法可以使make测试执行ctest -V而不是ctest的操作?ctest输出看起来非常不完整,只是说有一个测试。
拉吉夫


4

避免头痛:

make all test

对于我来说,它是开箱即用的,并且会在运行测试之前建立依赖关系。鉴于这很简单,它几乎使本机make test功能变得很方便,因为即使您的代码已损坏,它也使您可以选择运行最后的编译测试。


1
不适用于CDash。您必须调用make all && ctest,然后该建筑物才不是上载测试的一部分。因此,构建警告或错误不可见。
usr1234567

2
如果您想要并行构建,也不能很好地工作,因为两者将并行运行:需要make -j4 all && make test。而且,使用非Make构建工具时,它也很脆弱。
poolie

4

如果您使用的是CMake> = 3.7,则建议的方法是使用灯具

add_executable(test test.cpp)
add_test(test_build
  "${CMAKE_COMMAND}"
  --build "${CMAKE_BINARY_DIR}"
  --config "$<CONFIG>"
  --target test
)
set_tests_properties(test_build PROPERTIES FIXTURES_SETUP    test_fixture)
add_test(test test)
set_tests_properties(test       PROPERTIES FIXTURES_REQUIRED test_fixture)

这将执行以下操作:

  • 添加test从中构建的可执行目标test.cpp
  • 添加一个test_build运行Cmake的“测试”以构建目标test
  • test_build测试标记为夹具的设置任务test_fixture
  • 添加一个test仅运行test可执行文件的测试
  • 标记test测试需要夹具test_fixture

因此,每次test要运行测试时,它都会首先运行test test_build,它会构建必要的可执行文件。


如果$<CONFIG>未设置,--target则将成为的参数--config
loshad vtapkah

我相信$<CONFIG>永远是非空的。它是配置名称的生成器表达式:cmake.org/cmake/help/latest/manual / ...我将编辑答案以将其包装在引号中,只是因为它没有区别。
约翰·弗里曼

你怎么跑cmake?我做的是这样的:mkdir build; cd build; cmake ..; make。看起来没有任何默认值,并且所有相关变量都是空的,直到CMAKE_BUILD_TYPE手动设置为止。(当前在Debian 10上,没有检查其他平台)
loshad vtapkah 19/12/30

1

这是我锤击并一直使用的:

set(${PROJECT_NAME}_TESTS a b c)

enable_testing()
add_custom_target(all_tests)
foreach(test ${${PROJECT_NAME}_TESTS})
        add_executable(${test} EXCLUDE_FROM_ALL ${test}.cc)
        add_test(NAME ${test} COMMAND $<TARGET_FILE:${test}>)
        add_dependencies(all_tests ${test})
endforeach(test)

build_command(CTEST_CUSTOM_PRE_TEST TARGET all_tests)
string(CONFIGURE \"@CTEST_CUSTOM_PRE_TEST@\" CTEST_CUSTOM_PRE_TEST_QUOTED ESCAPE_QUOTES)
file(WRITE "${CMAKE_BINARY_DIR}/CTestCustom.cmake" "set(CTEST_CUSTOM_PRE_TEST ${CTEST_CUSTOM_PRE_TEST_QUOTED})" "\n")

青年汽车


0

Derrick的答案经过简化和评论:

# It is impossible to make target "test" depend on "all":
# https://gitlab.kitware.com/cmake/cmake/-/issues/8774
# Set a magic variable in a magic file that tells ctest
# to invoke the generator once before running the tests:
file(WRITE "${CMAKE_BINARY_DIR}/CTestCustom.cmake"
    "set(CTEST_CUSTOM_PRE_TEST ${CMAKE_MAKE_PROGRAM})\n"
)

这不是完全正确的,因为它不能解决running的并发问题ninja all test,以防万一有人这样做。相反,因为现在有两个忍者进程。

(Ftr,我也在这里共享了此解决方案。)


-3

以上所有答案都是完美的。但是实际上CMake使用CTest作为其测试工具,因此执行任务的标准方法(我认为是)是:

enable_testing ()
add_test (TestName TestCommand)
add_test (TestName2 AnotherTestCommand)

然后运行cmake的使建立的目标。之后,您可以运行make test,也可以只运行

ctest

您将得到结果。这是在CMake 2.8下测试的。

在以下位置检查详细信息:http : //cmake.org/Wiki/CMake/Testing_With_CTest#Simple_Testing


5
不推荐使用,因为有时您只想构建实际运行的测试所需的目标。
Dave Abrahams

12
这个答案似乎误解了问题:OP已经在做完全按照这个答案建议:使用CTEST, ,enable_testing()add_test()等的问题是,他有手动发出之前,运行测试构建命令。他希望make test目标根据需要自动构建测试可执行文件。
bames53 2014年

-4

所有的答案都是好的,但它们暗示着违反传统,只能凭命令进行测试make test。我已经完成了这个技巧:

add_test(NAME <mytest>
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMAND sh -c "make <mytarget>; $<TARGET_FILE:<mytarget>>")

这意味着测试由构建(可选)和运行可执行目标组成。


6
:-D规则1:不要使用没有sh的系统。你知道这样的系统吗?
dyomas 2014年

11
是的,Windows是其中之一。
David Faure

3
这也被硬编码到makeCMake的为其他构建工具生成脚本的功能,并且丢失了。
poolie
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.