CMake & CTest: make test erstellt keine Tests

87

Ich versuche CTest in CMake, um einige meiner Tests automatisch mit make testtarget auszuführen . Das Problem ist, dass CMake nicht "versteht", dass der Test, den ich ausführen möchte, erstellt werden muss, da er Teil des Projekts ist.

Daher suche ich nach einer Möglichkeit, diese Abhängigkeit explizit anzugeben.

claf
quelle

Antworten:

78

Es ist wohl ein Fehler in CMake (zuvor hier verfolgt ), dass dies nicht sofort funktioniert. Eine Problemumgehung besteht darin, Folgendes zu tun:

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

Dann können Sie ausführen make checkund es wird kompiliert und der Test ausgeführt. Wenn Sie mehrere Tests haben, müssen Sie diese DEPENDS exe1 exe2 exe3 ...in der obigen Zeile verwenden.

richq
quelle
1
Ich denke also, dass das Ziel "Test machen" nicht verwendet wird, da Sie anscheinend einen anderen Zielnamen im Befehl add_custom_target auswählen müssen.
Claf
Ja. Der einzige Unterschied zwischen "make test" und "make check" besteht darin, dass erstere zuerst "Running tests ..." anzeigt und keine Build-Abhängigkeiten überprüft.
Richq
2
@rq - aber wie kann ich das mit mehreren Projekten machen (wenn eine CMakeLists.txt ein Unterprojekt eines anderen ist), so dass jedes checkZiel definiert und sie kollidieren können
Artyom
2
@Artyom - in diesem Fall ist es wahrscheinlich besser, nur das Äquivalent "make all test" zu verwenden. Tatsächlich mache ich das sowieso.
Richq
4
Tatsächlich betrachten einige es als eine Funktion (kein Fehler) von cmake, dass Sie "make test" ausführen und die Tests einfach so ausführen können, wie sie sind, ohne zuerst
neue
51

Es gibt tatsächlich eine Möglichkeit zu verwenden make test. Sie müssen den Build der ausführbaren Testdatei als einen der Tests definieren und dann Abhängigkeiten zwischen den Tests hinzufügen. Das ist:

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
quelle
11
Dies ist die einzige, die skaliert und Sie nicht zwingt, die Ziele "Alle erstellen" zu erstellen, nur um den Test auszuführen. Ein möglicher Nachteil: Details zu Erstellungsfehlern in den Binärdateien werden nur in der generierten LastTest.log-Datei und nicht in stdout / stderr
Dave Abrahams
2
Gute Antwort! Sie sollten die Konfiguration jedoch zum Build-Ziel hinzufügen. Andernfalls können die Tests nicht in allen Konfigurationen ausgeführt werden. add_test (NAME "$ {ARGV0} _BUILD" COMMAND "$ {CMAKE_COMMAND}" --build $ {CMAKE_BINARY_DIR} --target $ {target} "--config" "$ <CONFIG>")
Daniel
1
Dies verstopft den Testreporter mit einer Reihe von falschen Tests.
Wenn Sie CMake> = 3.7 verwenden, wird empfohlen, Fixtures zu verwenden. Siehe meine Antwort unten.
John Freeman
13

Ich benutze eine Variante von Richqs Antwort. In der obersten Ebene CMakeLists.txtfüge ich ein benutzerdefiniertes Ziel hinzu build_and_test, um alle Tests zu erstellen und auszuführen:

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

In den verschiedenen Unterprojektdateien CMakeLists.txtunter test/füge ich jede ausführbare Testdatei als Abhängigkeit von 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)

Mit diesem Ansatz, ich brauche nur make build_and_teststatt make test(oder make all test), und es hat den Vorteil, nur Testcode Aufbau (und ihre Abhängigkeiten). Schade, dass ich den Zielnamen nicht verwenden kann test. In meinem Fall ist es nicht so schlimm , weil ich einen Top-Level - Skript, das funktioniert out-of-Baum Debug- und Release (und Cross-kompilierte) baut durch den Aufruf cmakeund dann make, und es übersetzt testin build_and_test.

Offensichtlich ist das GTest-Zeug nicht erforderlich. Ich habe gerade Google Test verwendet / mag und wollte ein vollständiges Beispiel für die Verwendung mit CMake / CTest teilen. Meiner Meinung nach hat dieser Ansatz auch den Vorteil, dass ich ihn verwenden kann ctest -V, der die Google Test-Ausgabe anzeigt, während die Tests ausgeführt werden:

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
quelle
Gibt es in diesem Beispiel eine Möglichkeit, make test dazu zu bringen, das zu tun, was ctest -V anstelle von ctest tut? Die ctest-Ausgabe sieht sehr unvollständig aus und sagt nur, dass es einen einzelnen Test gibt.
Rajiv
6

Wenn Sie versuchen zu emulieren make check, finden Sie diesen Wiki-Eintrag möglicherweise nützlich:

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

Ich habe gerade überprüft, ob dies mit Erfolg funktioniert (CMake 2.8.10).

Samuel
quelle
1
Dadurch werden beim Ausführen alle ausführbaren Dateien erstellt make check. Für Tests mit dominierenden Kompilierungszeiten ist dies ctest -Runbrauchbar.
usr1234567
4

Sparen Sie sich die Kopfschmerzen:

make all test

Funktioniert sofort für mich und erstellt Abhängigkeiten, bevor der Test ausgeführt wird. In Anbetracht dessen, wie einfach dies ist, ist die native make testFunktionalität fast praktisch, da Sie die Möglichkeit haben, die letzten Kompilierungstests auszuführen, selbst wenn Ihr Code fehlerhaft ist.

quant
quelle
1
Funktioniert nicht mit CDash. Sie müssen make all && ctest aufrufen und dann ist das Gebäude nicht Teil des hochgeladenen Tests. Build-Warnungen oder Fehler sind daher nicht sichtbar.
usr1234567
2
Funktioniert auch nicht gut, wenn Sie einen parallelen Build wünschen, da die beiden parallel ausgeführt werden: Sie benötigen make -j4 all && make test. Und es ist auch schuppig mit einem Nicht-Make-Build-Tool.
Poolie
3

Wenn Sie CMake> = 3.7 verwenden, wird empfohlen, Fixtures zu verwenden :

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)

Dies bewirkt Folgendes:

  • Fügt ein testausführbares Ziel hinzu, aus dem erstellt wurdetest.cpp
  • Fügt einen test_build"Test" hinzu, der Cmake ausführt, um ein Ziel zu erstellentest
  • Markiert den test_buildTest als Einrichtungsaufgabe des Gerätstest_fixture
  • Fügen Sie einen testTest hinzu, der nur die testausführbare Datei ausführt
  • Markiert den testTest, um eine Befestigung zu benötigen test_fixture.

Jedes Mal, wenn ein Test ausgeführt testwerden soll, wird zuerst ein Test ausgeführt test_build, der die erforderliche ausführbare Datei erstellt.

John Freeman
quelle
Wenn $<CONFIG>nicht gesetzt, --targetwird das zum Argument für die --config.
Loshad Vtapkah
Ich glaube $<CONFIG>ist immer nicht leer. Es ist ein Generatorausdruck für den Konfigurationsnamen: cmake.org/cmake/help/latest/manual/… Ich werde die Antwort bearbeiten, um sie trotzdem in Anführungszeichen zu setzen, nur weil es keinen Unterschied macht.
John Freeman
Wie laufen Sie cmake? Ich mache das so : mkdir build; cd build; cmake ..; make. Und es sieht so aus, als gäbe es keine Standardeinstellungen und alle zugehörigen Variablen sind leer, bis sie CMAKE_BUILD_TYPEmanuell festgelegt werden. (Derzeit auf Debian 10, andere Plattformen nicht überprüft)
Loshad Vtapkah
0

Das habe ich herausgehämmert und benutzt:

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

Bohrturm
quelle
-3

Alle obigen Antworten sind perfekt. Tatsächlich verwendet CMake CTest als Testwerkzeug. Die Standardmethode (ich denke es ist) für die Mission lautet:

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

Führen Sie dann cmake aus und machen Sie , um die Ziele zu erstellen. Danach können Sie entweder make test ausführen oder einfach ausführen

ctest

Sie erhalten das Ergebnis. Dies wird unter CMake 2.8 getestet.

Überprüfen Sie die Details unter: http://cmake.org/Wiki/CMake/Testing_With_CTest#Simple_Testing

holmescn
quelle
5
Downvoted, weil Sie manchmal nur die Ziele erstellen möchten, die für die tatsächlich ausgeführten Tests erforderlich sind.
Dave Abrahams
12
Diese Antwort scheint die Frage falsch zu verstehen: Die OP schon genau tut , wie diese Antwort empfiehlt: Verwenden CTest, enable_testing(), add_test()usw. Das Problem ist , dass er den Build - Befehl vor dem Ausführen von Tests manuell ausgeben muss. Er möchte, dass das make testZiel die ausführbaren Testdateien nach Bedarf automatisch erstellt.
Bames53
-4

Alle Antworten sind gut, aber sie implizieren einen Verstoß gegen die Tradition, um einen Test auf Befehl durchzuführen make test. Ich habe diesen Trick gemacht:

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

Dies bedeutet, dass der Test aus dem Erstellen (optional) und Ausführen eines ausführbaren Ziels besteht.

Dyome
quelle
6
:-D Regel 1: Verwenden Sie kein System ohne sh. Kennen Sie ein solches System?
Dyomas
11
Ja, Windows ist eines davon.
David Faure
3
Dies ist auch fest codiert makeund verliert die CMake-Funktion zum Generieren von Skripten für andere Build-Tools.
Poolie