CMake & CTest: thực hiện thử nghiệm không tạo thử nghiệm


89

Tôi đang thử CTest trong CMake để tự động chạy một số thử nghiệm của mình bằng make testtarget. Vấn đề là CMake không "hiểu" rằng bài kiểm tra tôi sẵn sàng chạy phải được xây dựng vì nó là một phần của dự án.

Vì vậy, tôi đang tìm cách xác định rõ ràng sự phụ thuộc này.

Câu trả lời:


79

thể cho là một lỗi trong CMake (đã được theo dõi trước đây ở đây ) khiến điều này không hoạt động tốt. Một cách giải quyết là làm như sau:

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

Sau đó, bạn có thể chạy make checkvà nó sẽ biên dịch và chạy thử nghiệm. Nếu bạn có một số bài kiểm tra, thì bạn sẽ phải sử dụng DEPENDS exe1 exe2 exe3 ...trong dòng trên.


1
vì vậy tôi đoán rằng mục tiêu "thực hiện kiểm tra" sẽ vẫn không được sử dụng vì có vẻ như bạn phải chọn một tên mục tiêu khác trong lệnh add_custom_target?
claf

Vâng. Sự khác biệt duy nhất giữa "thực hiện kiểm tra" và "thực hiện kiểm tra" là trước đó hiển thị "Đang chạy thử nghiệm ..." trước tiên và không kiểm tra bất kỳ phụ thuộc xây dựng nào.
richq

2
@rq - nhưng làm thế nào tôi có thể làm điều này với nhiều dự án (khi một CMakeLists.txt là Tiểu dự án khác) vì vậy mỗi người ta sẽ xác định checkmục tiêu và họ có thể va chạm
Artyom

2
@Artyom - trong trường hợp đó, bạn có lẽ tốt hơn nên chỉ sử dụng "make all test" tương đương. Trong thực tế, đây là những gì tôi làm.
richq

4
Trên thực tế, một số coi đó là một tính năng (không phải là một lỗi) của cmake mà bạn có thể chạy "make test" và chỉ cần chạy các bài kiểm tra như họ đang có mà không làm bất kỳ tái xây dựng đầu tiên ...
DLRdave

55

Thực ra có một cách để sử dụng make test. Bạn cần phải xác định việc xây dựng tệp thực thi thử nghiệm là một trong các thử nghiệm và sau đó thêm các phụ thuộc giữa các thử nghiệm. Đó là:

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
Đây là cách duy nhất mở rộng quy mô và không buộc bạn phải xây dựng mục tiêu "thực hiện tất cả" chỉ để chạy thử nghiệm. Một nhược điểm có thể: chi tiết về xây dựng các lỗi trên những chương trình chỉ hiển thị trong file LastTest.log tạo ra và không phải trên stdout / stderr
Dave Abrahams

2
Câu trả lời tốt! Tuy nhiên, bạn nên thêm cấu hình vào mục tiêu xây dựng. Nếu không, không thể chạy thử nghiệm trong tất cả các cấu hình. add_test (NAME "$ {ARGV0} _BUILD" COMMAND "$ {CMAKE_COMMAND}" - xây dựng $ {CMAKE_BINARY_DIR} --target $ {target} "--config" "$ <CONFIG>")
Daniel

1
Điều này làm tắc nghẽn các phóng viên thử nghiệm với một loạt các bài kiểm tra rởm.

Nếu bạn đang sử dụng CMake> = 3.7, cách tiếp cận được khuyến nghị là sử dụng đồ đạc. Xem câu trả lời của tôi dưới đây.
John Freeman

13

Tôi sử dụng một biến thể của câu trả lời richq. Ở cấp cao nhất CMakeLists.txt, tôi thêm một mục tiêu tùy chỉnh build_and_test, để xây dựng và chạy tất cả các thử nghiệm:

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

Trong các CMakeLists.txttệp dự án con khác nhau bên dưới test/, tôi thêm từng tệp thực thi thử nghiệm dưới dạng phụ thuộc của 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)

Với cách tiếp cận này, tôi chỉ cần make build_and_testthay vì make test(hoặc make all test) và nó có lợi ích là chỉ xây dựng mã thử nghiệm (và các phụ thuộc của nó). Thật tiếc khi tôi không thể sử dụng tên mục tiêu test. Trong trường hợp của tôi, nó không quá tệ vì tôi có một tập lệnh cấp cao nhất thực hiện gỡ lỗi và phát hành (và biên dịch chéo) các bản dựng bằng cách gọi cmakevà sau đó make, và nó được dịch testsang build_and_test.

Rõ ràng, nội dung GTest không bắt buộc. Tôi chỉ tình cờ sử dụng / thích Google Test và muốn chia sẻ một ví dụ hoàn chỉnh về việc sử dụng nó với CMake / CTest. IMHO, cách tiếp cận này cũng có lợi ích là cho phép tôi sử dụng ctest -V, hiển thị kết quả Kiểm tra của Google trong khi các bài kiểm tra chạy:

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

Trong ví dụ này, có cách nào để thực hiện thử nghiệm thực hiện những gì ctest -V làm thay vì ctest không? Đầu ra ctest trông rất không đầy đủ và chỉ nói rằng có một bài kiểm tra duy nhất.
Rajiv

6

Nếu bạn đang cố gắng mô phỏng make check, bạn có thể thấy mục nhập wiki này hữu ích:

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

Tôi vừa kiểm tra xem nó có thành công không (CMake 2.8.10).


1
Điều này sẽ xây dựng tất cả các tệp thực thi khi chạy make check. Đối với các bài kiểm tra có thời gian biên dịch chiếm ưu thế, điều này ctest -Rvô ích.
usr1234567

4

Tự cứu mình khỏi đau đầu:

make all test

Hoạt động hiệu quả đối với tôi và sẽ xây dựng các phụ thuộc trước khi chạy thử nghiệm. Với mức độ đơn giản của điều này, nó gần như làm cho make testchức năng gốc trở nên thuận tiện vì nó cung cấp cho bạn tùy chọn chạy các thử nghiệm biên dịch cuối cùng ngay cả khi mã của bạn bị hỏng.


1
Không hoạt động với CDash. Bạn phải gọi thực hiện tất cả && ctest và sau đó tòa nhà không phải là một phần của thử nghiệm được tải lên. Vì vậy, các cảnh báo hoặc lỗi xây dựng không hiển thị.
usr1234567

2
Cũng không hoạt động tốt nếu bạn muốn xây dựng song song, vì cả hai sẽ chạy song song: bạn cần make -j4 all && make test. Và nó cũng dễ hỏng khi sử dụng một công cụ xây dựng không phải Make.
poolie

4

Nếu bạn đang sử dụng CMake> = 3.7, thì cách tiếp cận được khuyến nghị là sử dụng đồ đạc :

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)

Điều này thực hiện như sau:

  • Thêm một testmục tiêu thực thi được xây dựng từtest.cpp
  • Thêm một test_build"bài kiểm tra" chạy Cmake để xây dựng mục tiêutest
  • Đánh dấu test_buildbài kiểm tra là một nhiệm vụ thiết lập của vật cố địnhtest_fixture
  • Thêm một testbài kiểm tra chỉ chạy testtệp thực thi
  • Đánh dấu testbài kiểm tra cần cố định test_fixture.

Vì vậy, mỗi khi testchạy thử nghiệm test_build, trước tiên nó sẽ chạy thử nghiệm , điều này sẽ xây dựng tệp thực thi cần thiết.


Nếu $<CONFIG>không được đặt thì --targetsẽ trở thành đối số cho --config.
loshad vtapkah

Tôi tin rằng $<CONFIG>luôn luôn không trống rỗng. Nó là một biểu thức trình tạo cho tên cấu hình: cmake.org/cmake/help/latest/manual/… Tôi sẽ chỉnh sửa câu trả lời để đặt nó trong dấu ngoặc kép chỉ vì nó không có gì khác biệt.
John Freeman

Làm thế nào để bạn chạy cmake? Tôi làm theo cách này: mkdir build; cd build; cmake ..; make. Và có vẻ như không có bất kỳ giá trị mặc định nào và tất cả các biến liên quan đều trống, cho đến khi CMAKE_BUILD_TYPEđược đặt theo cách thủ công. (hiện tại trên Debian 10, đã không kiểm tra nền tảng khác)
loshad vtapkah

1

Đây là những gì tôi đã đúc kết ra và đã được sử dụng:

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

Câu trả lời của Derrick, được đơn giản hóa và nhận xét:

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

Nó không hoàn toàn chính xác, vì nó không giải quyết được vấn đề đồng thời khi chạy ninja all test, trong trường hợp bất kỳ ai làm điều đó. Ngược lại, bởi vì bây giờ, bạn có hai quy trình ninja.

(Ftr, tôi cũng đã chia sẻ giải pháp này ở đây .)


-3

Tất cả các câu trả lời trên đều hoàn hảo. Nhưng thực ra CMake sử dụng CTest làm công cụ kiểm tra, vì vậy phương pháp tiêu chuẩn (tôi nghĩ là như vậy) để thực hiện sứ mệnh là:

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

Sau đó chạy cmakethực hiện để xây dựng các mục tiêu. Sau đó, bạn có thể chạy thử nghiệm hoặc chỉ chạy

ctest

bạn sẽ nhận được kết quả. Điều này được thử nghiệm theo CMake 2.8.

Kiểm tra chi tiết tại: http://cmake.org/Wiki/CMake/Testing_With_CTest#Simple_Testing


5
Bị phản đối vì đôi khi bạn chỉ muốn xây dựng các mục tiêu cần thiết cho các thử nghiệm đang thực sự được chạy.
Dave Abrahams

12
Câu trả lời này dường như hiểu sai câu hỏi: Các OP đã làm đúng như câu trả lời này khuyến cáo: Sử dụng CTest, enable_testing(), add_test(), vv Vấn đề là hắn chỉ còn tự hành xây dựng lệnh trước khi chạy thử nghiệm. Anh ta muốn make testmục tiêu tự động xây dựng các tệp thực thi thử nghiệm khi cần thiết.
bames53

-4

Tất cả các câu trả lời đều tốt, nhưng chúng ngụ ý vi phạm truyền thống chạy kiểm tra bằng lệnh make test. Tôi đã thực hiện thủ thuật này:

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

Điều này có nghĩa là kiểm tra bao gồm xây dựng (tùy chọn) và chạy mục tiêu thực thi.


6
:-D Quy tắc # 1: Không sử dụng hệ thống mà không có sh. Bạn có biết hệ thống như vậy?
dyomas

11
Có, Windows là một trong số này.
David Faure

3
Điều này cũng được mã hóa cứng makevà làm mất tính năng tạo tập lệnh cho các công cụ xây dựng khác của CMake.
poolie
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.