CMake & CTest: ทำการทดสอบไม่ได้สร้างการทดสอบ


91

ฉันกำลังลอง CTest ใน CMake เพื่อทำการทดสอบบางอย่างโดยอัตโนมัติโดยใช้make testเป้าหมาย ปัญหาคือ CMake ไม่ "เข้าใจ" ว่าการทดสอบที่ฉันยินดีจะเรียกใช้จะต้องถูกสร้างขึ้นเนื่องจากเป็นส่วนหนึ่งของโครงการ

ดังนั้นฉันกำลังมองหาวิธีระบุการอ้างอิงนี้อย่างชัดเจน

คำตอบ:


81

มันเป็นเนื้อหาข้อผิดพลาดใน CMake (ติดตามก่อนหน้านี้ที่นี่ ) ที่นี้ไม่ได้ออกมาจากกล่อง วิธีแก้ปัญหาคือทำสิ่งต่อไปนี้:

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

จากนั้นคุณสามารถเรียกใช้make checkและจะรวบรวมและเรียกใช้การทดสอบ หากคุณมีการทดสอบหลายครั้งคุณจะต้องใช้DEPENDS exe1 exe2 exe3 ...ในบรรทัดด้านบน


1
ดังนั้นฉันเดาว่าเป้าหมาย "ทำการทดสอบ" จะยังคงไม่ได้ใช้งานเนื่องจากดูเหมือนว่าคุณต้องเลือกชื่อเป้าหมายอื่นในคำสั่ง add_custom_target?
claf

ใช่. ความแตกต่างเพียงอย่างเดียวระหว่าง "make test" และ "make check" คือรายการก่อนหน้านี้จะแสดง "Running testing ... " ก่อนและไม่ได้ตรวจสอบการอ้างอิงของบิวด์ใด ๆ
richq

2
@rq - แต่ฉันจะทำสิ่งนี้กับหลาย ๆ โปรเจ็กต์ได้อย่างไร (เมื่อหนึ่ง CMakeLists.txt เป็นโปรเจ็กต์ย่อยของโปรเจ็กต์อื่น ๆ ) ดังนั้นแต่ละโปรเจ็กต์จะกำหนดcheckเป้าหมายและอาจชนกัน
Artyom

2
@Artyom - ในกรณีนี้คุณน่าจะดีกว่าที่จะใช้ "make all test" ที่เทียบเท่า อันที่จริงนี่คือสิ่งที่ฉันทำอยู่แล้ว
richq

4
อันที่จริงบางคนคิดว่าเป็นคุณลักษณะ (ไม่ใช่จุดบกพร่อง) ของ cmake ที่คุณสามารถเรียกใช้ "ทำการทดสอบ" และเรียกใช้การทดสอบได้ตามที่เป็นอยู่โดยไม่ต้องสร้างใหม่ก่อน ...
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
คำตอบที่ดี! คุณควรเพิ่ม config ให้กับ build target ด้วย มิฉะนั้นจะไม่สามารถเรียกใช้การทดสอบในการกำหนดค่าทั้งหมดได้ add_test (NAME "$ {ARGV0} _BUILD" COMMAND "$ {CMAKE_COMMAND}" - สร้าง $ {CMAKE_BINARY_DIR} --target $ {target} "--config" "$ <CONFIG>")
Daniel

1
สิ่งนี้ทำให้ผู้รายงานทดสอบอุดตันด้วยการทดสอบปลอมมากมาย

หากคุณใช้ CMake> = 3.7 แนวทางที่แนะนำคือใช้อุปกรณ์ติดตั้ง ดูคำตอบของฉันด้านล่าง
John Freeman

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

ในตัวอย่างนี้มีวิธีในการทำการทดสอบเพื่อทำสิ่งที่ ctest -V ทำแทน ctest หรือไม่? ผลลัพธ์ ctest ดูไม่สมบูรณ์มากและบอกเพียงว่ามีการทดสอบเพียงครั้งเดียว
Rajiv

6

หากคุณกำลังพยายามเลียนแบบmake checkคุณอาจพบว่ารายการวิกินี้มีประโยชน์:

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

ฉันเพิ่งตรวจสอบว่านั่นคือสิ่งที่พูดด้วยความสำเร็จ (CMake 2.8.10)


1
นี้จะช่วยสร้าง executables make checkทั้งหมดเมื่อทำงาน สำหรับการทดสอบที่มีเวลาการคอมไพล์ที่เหนือกว่าจะทำให้ctest -Rไร้ประโยชน์
usr1234567

4

ช่วยตัวเองไม่ให้ปวดหัว:

make all test

ทำงานนอกกรอบสำหรับฉันและจะสร้างการอ้างอิงก่อนที่จะเรียกใช้การทดสอบ เมื่อพิจารณาถึงความเรียบง่ายนี้มันเกือบจะทำให้make testฟังก์ชันเนทีฟสะดวกสบายเพราะมันทำให้คุณมีตัวเลือกในการเรียกใช้การทดสอบการคอมไพล์ล่าสุดแม้ว่าโค้ดของคุณจะเสียก็ตาม


1
ไม่ทำงานกับ CDash คุณต้องโทรทำการทดสอบ && 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ไฟล์ปฏิบัติการ
  • เครื่องหมายการทดสอบเพื่อความจำเป็นในการติดตั้งtesttest_fixture

ดังนั้นทุกครั้งที่ต้องทำการทดสอบtestจะต้องทำการทดสอบtest_buildก่อนซึ่งจะสร้างไฟล์ปฏิบัติการที่จำเป็น


หาก$<CONFIG>ไม่ได้ตั้งค่า--targetจะกลายเป็นอาร์กิวเมนต์สำหรับ--config.
loshad vtapkah

ฉันเชื่อ$<CONFIG>เสมอว่าไม่ว่างเปล่า มันเป็นนิพจน์ตัวสร้างสำหรับชื่อคอนฟิกูเรชัน: cmake.org/cmake/help/latest/manual/…ฉันจะแก้ไขคำตอบเพื่อรวมไว้ในเครื่องหมายคำพูดต่อไปเพราะมันไม่ได้สร้างความแตกต่าง
John Freeman

คุณจะวิ่งได้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

คำตอบของ 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"
)

ไม่ถูกต้องอย่างสมบูรณ์เนื่องจากไม่สามารถแก้ปัญหาการทำงานพร้อมกันของการทำงาน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
คำตอบนี้ดูเหมือนว่าจะเข้าใจผิดคำถาม: สหกรณ์อยู่แล้วทำตรงตามที่คำตอบนี้แนะนำ: การใช้ 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 คุณรู้จักระบบดังกล่าวหรือไม่?
dyomas

11
ใช่ Windows เป็นหนึ่งในนั้น
David Faure

3
นอกจากนี้ยังเข้ารหัสmakeและสูญเสียคุณลักษณะของ CMake ในการสร้างสคริปต์สำหรับเครื่องมือสร้างอื่น ๆ
สระว่ายน้ำ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.