CMake & CTest: тест make не створює тести


89

Я намагаюся CTest в CMake для того, щоб автоматично запускати деякі свої тести за допомогою make testtarget. Проблема в тому, що CMake не "розуміє", що тест, який я готовий провести, повинен бути побудований, оскільки він є частиною проекту.

Тому я шукаю спосіб явно вказати цю залежність.

Відповіді:


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" - це те, що перше показує "Запуск тестів ..." спочатку і не перевіряє ніяких залежностей збірки.
richq

2
@rq - але як я можу це зробити з кількома проектами (коли один CMakeLists.txt є підпроектом іншого), щоб кожен з них визначив checkціль, і вони можуть зіткнутися
Артем

2
@Artyom - у такому випадку вам, мабуть, краще просто використовувати еквівалент "зробити все тестом". Насправді цим я все одно займаюся.
richq

4
Насправді, деякі вважають особливістю (а не помилкою) cmake те, що ви можете запустити "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>")
Даніель

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, і це перекладається testв build_and_test.

Очевидно, що речі GTest не потрібні. Я випадково використовую / подобається Google Test, і я хочу поділитися повним прикладом його використання з CMake / CTest. IMHO, цей підхід також має перевагу, що дозволяє мені використовувати ctest -V, що показує результати випробувань Google під час запуску тестів:

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 test, щоб зробити те, що робить ctest -V замість ctest? Результат ctest виглядає дуже неповним і просто говорить про те, що існує один тест.
Раджів

6

Якщо ви намагаєтеся наслідувати make check, вам може здатися , що цей запис у вікі корисний:

http://www.cmake.org/Wiki/CMakeEmulateMakeCheck

Я щойно перевірив, що робить те, що він каже, з успіхом (CMake 2.8.10).


1
Це створить усі виконувані файли під час запуску make check. Для тестів з домінуючим часом складання це робить ctest -Rмарним.
usr1234567

4

Збережіть собі головний біль:

make all test

Для мене це працює нестандартно і будує залежності перед запуском тесту. Враховуючи, наскільки це просто, це майже робить рідну make testфункціональність зручною, оскільки вона дає можливість запускати останні компіляційні тести, навіть якщо ваш код зламаний.


1
Не працює з CDash. Вам потрібно зателефонувати зробити все && ctest, і тоді будівля не є частиною завантаженого тестування. Тож попередження про помилки або помилки не видно.
usr1234567

2
Також не працює добре, якщо ви хочете паралельну збірку, оскільки обидві вони будуть працювати паралельно: вам потрібно make -j4 all && make test. І це також розшаровується, використовуючи інструмент побудови, який не робить.
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_build, він спочатку запускає тест , який створює необхідний виконуваний файл.


Якщо $<CONFIG>не встановлено --target, аргумент для аргументу --config.
лошад втапках

Я вважаю $<CONFIG>, що завжди не порожньо. Це вираз генератора для імені конфігурації: cmake.org/cmake/help/latest/manual/... Я відредагую відповідь, щоб у будь-якому випадку обернути його в лапки, лише тому, що це не має значення.
Джон Фрімен,

Як ти біжиш cmake? Я роблю це так: mkdir build; cd build; cmake ..; make. І схоже, що за замовчуванням немає жодних замовчувань, а всі пов’язані змінні порожні, поки CMAKE_BUILD_TYPEне встановлюється вручну. (в даний час на Debian 10, не перевіряв інші платформи)
loshad vtapkah

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

YMMV


0

Відповідь Дерріка, спрощена та прокоментована:

# 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"
)

Це не зовсім правильно, оскільки це не вирішує проблему паралельності запуску ninja all test, якщо хтось це зробить. Навпаки, адже зараз у вас є два процеси ніндзя.

(Ftr, я також поділився цим рішенням тут .)


-3

Усі наведені вище відповіді ідеальні. Але насправді CMake використовує CTest як інструмент тестування, тому стандартним методом (я думаю, що він є) є місія:

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

Потім запустіть cmake і make для побудови цілей. Після цього ви можете або запустити make test , або просто запустити

ctest

ви отримаєте результат. Це перевірено в CMake 2.8.

Перевірте деталі на: http://cmake.org/Wiki/CMake/Testing_With_CTest#Simple_Testing


5
Проголосовано проти, оскільки іноді потрібно лише побудувати цілі, необхідні для фактично запущених тестів.
Dave Abrahams

12
Відповідь на це питання , здається, неправильно питання: ОР вже робить саме так , як ця відповідь рекомендує: Використання CTest, enable_testing(), add_test()і т.д. Проблема полягає в тому, що він повинен вручну виконати команду збірки до запуску тестів. Він хоче, щоб make testціль автоматично створювала тестові виконувані файли за необхідності.
bames53

-4

Усі відповіді хороші, але вони означають порушення традиції проводити тест за командою make test. Я зробив цей трюк:

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

Це означає, що тест складається з побудови (за бажанням) та запуску виконуваної цілі.


6
:-D Правило №1: Не використовуйте систему без sh. Ви знаєте таку систему?
діома

11
Так, Windows - одна з таких.
Девід Форе

3
Це також жорстко закодовано makeі втрачає можливість CMake створювати сценарії для інших інструментів побудови.
Poolie
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.