CMake & CTest: make test nie tworzy testów

89

Próbuję CTest w CMake, aby automatycznie uruchamiać niektóre z moich testów przy użyciu make testcelu. Problem polega na tym, że CMake nie „rozumie”, że test, który chcę uruchomić, musi zostać zbudowany, ponieważ jest częścią projektu.

Dlatego szukam sposobu na jawne określenie tej zależności.

claf
źródło

Odpowiedzi:

79

Jest to prawdopodobnie jest błąd w CMake (śledzone wcześniej tutaj ), że to nie działa po wyjęciu z pudełka. Aby obejść ten problem, wykonaj następujące czynności:

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

Następnie możesz uruchomić, make checka on skompiluje i uruchomi test. Jeśli masz kilka testów, musisz użyć DEPENDS exe1 exe2 exe3 ...w powyższej linii.

richq
źródło
1
więc myślę, że cel "make test" pozostanie nieużywany, ponieważ wydaje się, że musisz wybrać inną nazwę celu w poleceniu add_custom_target?
claf
Tak. Jedyna różnica między „make test” a „make check” polega na tym, że pierwszy pokazuje najpierw „Running tests ...” i nie sprawdza żadnych zależności w budowaniu.
Richq
2
@rq - ale jak mogę to zrobić z wieloma projektami (gdy jeden CMakeLists.txt jest podprojektem innego), aby każdy z nich zdefiniował checkcel i mogą się zderzyć
Artem
2
@Artyom - w takim przypadku prawdopodobnie lepiej będzie po prostu użyć równoważnego „make all test”. Właściwie to i tak robię.
Richq
4
Właściwie niektórzy uważają to za funkcję (a nie błąd) cmake, że można uruchomić „make test” i po prostu uruchomić testy w takiej postaci, w jakiej są, bez konieczności uprzedniego ponownego
kompilowania
55

Właściwie jest sposób na użycie make test. Musisz zdefiniować kompilację pliku wykonywalnego testu jako jeden z testów, a następnie dodać zależności między testami. To jest:

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)
Iakov Nakhimovski
źródło
11
Jest to jedyny, który skaluje się i nie zmusza do tworzenia celów typu „make all” tylko po to, aby uruchomić test. Możliwym minusem: szczegóły błędów budować na binariów pojawić się tylko w generowanym pliku LastTest.log a nie na stdout / stderr
Dave Abrahams
2
Dobra odpowiedź! Należy jednak dodać konfigurację do celu kompilacji. W przeciwnym razie nie jest możliwe przeprowadzenie testów we wszystkich konfiguracjach. add_test (NAME "$ {ARGV0} _BUILD" COMMAND "$ {CMAKE_COMMAND}" --build $ {CMAKE_BINARY_DIR} --target $ {target} "--config" "$ <CONFIG>")
Daniel
1
To zatyka reportera testowego wieloma fałszywymi testami.
Jeśli używasz CMake> = 3.7, zalecanym podejściem jest użycie urządzeń. Zobacz moją odpowiedź poniżej.
John Freeman,
13

Używam wariantu odpowiedzi Richqa. Na najwyższym poziomie CMakeLists.txtdodaję cel niestandardowy build_and_testdo tworzenia i uruchamiania wszystkich testów:

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

W różnych CMakeLists.txtplikach podprojektów poniżej test/dodaję każdy plik wykonywalny testu jako zależność 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)

Przy takim podejściu po prostu muszę make build_and_testzamiast make test(lub make all test), a to ma tę zaletę, że buduje tylko kod testowy (i jego zależności). Szkoda, że ​​nie mogę użyć nazwy docelowej test. W moim przypadku nie jest tak źle, ponieważ mam skrypt najwyższego poziomu, który wykonuje debugowanie poza drzewem i zwalnia (i kompiluje krzyżowo), wywołując, cmakea następnie make, i przekłada się to testna build_and_test.

Oczywiście rzeczy GTest nie są wymagane. Po prostu używam / lubię Google Test i chciałem podzielić się pełnym przykładem użycia go z CMake / CTest. IMHO, to podejście ma również tę zaletę, że pozwala mi używać ctest -V, które pokazuje wyniki testu Google podczas wykonywania testów:

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
Trevor Robinson
źródło
W tym przykładzie, czy istnieje sposób, aby sprawić, by make test zrobił to, co robi ctest -V zamiast ctest? Wynik testu ctest wygląda na bardzo niekompletny i po prostu mówi, że jest jeden test.
Rajiv,
6

Jeśli próbujesz emulować make check, ten wpis wiki może okazać się przydatny:

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

Właśnie sprawdziłem, że robi to, co mówi, z sukcesem (CMake 2.8.10).

Samuel
źródło
1
Spowoduje to zbudowanie wszystkich plików wykonywalnych podczas działania make check. W przypadku testów z dominującymi czasami kompilacji jest to ctest -Rbezużyteczne.
usr1234567
4

Oszczędź sobie bólu głowy:

make all test

U mnie działa po wyjęciu z pudełka i przed uruchomieniem testu zbuduje zależności. Biorąc pod uwagę, jak proste jest to, prawie sprawia, że ​​natywna make testfunkcjonalność jest wygodna, ponieważ daje możliwość uruchomienia ostatnich testów kompilacji, nawet jeśli twój kod jest uszkodzony.

Quant
źródło
1
Nie działa z CDash. Musisz zadzwonić do make all && ctest, a wtedy budynek nie jest częścią przesłanych testów. Dlatego ostrzeżenia lub błędy kompilacji nie są widoczne.
usr1234567
2
Nie działa również dobrze, jeśli chcesz równoległej kompilacji, ponieważ oba będą działać równolegle: potrzebujesz make -j4 all && make test. Działa też niestabilnie przy użyciu narzędzia do kompilacji innego niż Make.
bilard
4

Jeśli używasz CMake> = 3.7, zalecanym podejściem jest użycie urządzeń :

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)

Robi to w następujący sposób:

  • Dodaje testwykonywalny cel zbudowany ztest.cpp
  • Dodaje test_build„test”, który uruchamia Cmake, aby zbudować celtest
  • Oznacza test_buildtest jako zadanie konfiguracyjne urządzeniatest_fixture
  • Dodaj testtest, który po prostu uruchamia testplik wykonywalny
  • Oznacza testtest jako wymagający zamocowania test_fixture.

Tak więc za każdym razem, gdy test testma być uruchomiony, najpierw uruchamia test test_build, który buduje niezbędny plik wykonywalny.

John Freeman
źródło
Jeśli $<CONFIG>nie jest ustawiona, --targetstanie się argumentem dla --config.
loshad vtapkah
Uważam, że $<CONFIG>jest zawsze niepusty. Jest to wyrażenie generatora dla nazwy konfiguracji: cmake.org/cmake/help/latest/manual/… I tak zmodyfikuję odpowiedź, aby umieścić ją w cudzysłowie, tylko dlatego, że nie ma to znaczenia.
John Freeman,
Jak biegasz cmake? Zrobić w ten sposób: mkdir build; cd build; cmake ..; make. Wygląda na to, że nie ma żadnych wartości domyślnych, a wszystkie powiązane zmienne są puste, dopóki nie CMAKE_BUILD_TYPEzostaną ustawione ręcznie. (obecnie na Debianie 10, innych platform nie sprawdzałem)
loshad vtapkah
1

Oto, co wymyśliłem i używałem:

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

Bom
źródło
0

Odpowiedź Derricka, uproszczona i skomentowana:

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

Nie jest to całkowicie poprawne, ponieważ nie rozwiązuje problemu współbieżności uruchamiania ninja all test, na wypadek gdyby ktoś to zrobił. Wręcz przeciwnie, ponieważ teraz masz dwa procesy ninja.

(Ftr, ja również wspólne rozwiązanie to tutaj .)

user2394284
źródło
-3

Wszystkie powyższe odpowiedzi są doskonałe. Ale tak naprawdę CMake używa CTest jako swoich narzędzi testowych, więc standardowa metoda (myślę, że tak) do wykonania misji to:

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

Następnie uruchom cmake i zrobić zbudować cele. Następnie możesz uruchomić make test lub po prostu uruchomić

ctest

otrzymasz wynik. Jest to testowane pod CMake 2.8.

Sprawdź szczegóły na: http://cmake.org/Wiki/CMake/Testing_With_CTest#Simple_Testing

holmescn
źródło
5
Negocjowany, ponieważ czasami chcesz tylko zbudować cele wymagane do faktycznie przeprowadzanych testów.
Dave Abrahams
12
Ta odpowiedź wydaje się rozumieją pytanie: PO jest już robi dokładnie jak ta odpowiedź poleca: Korzystanie CTest, enable_testing(), add_test(), itd. Problemem jest to, że musi ręcznie wydać polecenie build przed uruchomieniem testów. Chce, aby obiekt make testdocelowy automatycznie budował testowe pliki wykonywalne, jeśli to konieczne.
bames53
-4

Wszystkie odpowiedzi są dobre, ale sugerują naruszenie tradycji przeprowadzania testu na polecenie make test. Zrobiłem tę sztuczkę:

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

Oznacza to, że test składa się z kompilacji (opcjonalnie) i uruchomienia wykonywalnego celu.

dyomas
źródło
6
:-D Zasada nr 1: Nie używaj systemu bez sh. Znasz taki system?
dyomas,
11
Tak, Windows jest jednym z nich.
David Faure
3
Jest to również zakodowane na stałe makei traci funkcję CMake polegającą na generowaniu skryptów dla innych narzędzi do kompilacji.
poolie