I would like to be able in a similar manner as I can run cmake like
cmake --build <bld_directory>
to run ctest like
ctest --build <bld_directory>
Obviously running ctest from the <bld-directory> will work,
but it would be nice if I can just tell ctest where to look for its configuration file and where the test executables are located.
From the documentation it is not very clear (or I might not have looked in the right place) if this is possible at all or not.
It would great if somebody could shed some light on if this is possible or not ?
Many thanks,
Jiri
Since CMake 3.20 ctest has the option --test-dir for exactly that.
--test-dir <dir> Specify the directory in which to look for tests.
For CMake older than 3.20:
I couldn't find the way to do it through ctest options, but it is doable using the rule make test which is linked to ctest.
In the Makefile generated by cmake in your build folder you can find the rule:
#Special rule for the target test
test:
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running tests..."
/usr/bin/ctest --force-new-ctest-process $(ARGS)
.PHONY : test
make provides the option that you want with -C /path/to/build_directory/, and you can add any ctest options with ARGS='your ctest options here'
For example, from any directory in your system you can write:
make test -C /path/to/build_folder ARGS='-R SpecificTestIWantToRun -VV'
or
cmake --build <bld_directory> --target test -- ARGS="<ctest_args>"
Another approach without make, is to use parenthesis in your terminal to create a subshell. This will execute the command without changing the folder of your current shell.
(cd $build_folder; ctest -V)
Related
I have complicated project - a big tree, with CMakeLists.txt in each directory.
Once the cmake is done, the Makefile has test target which states
.PHONY test
test:
$(SHELL) -c
"$(CTEST) $(CTEST_FLAGS) --test-dir $(BUILD_PATH)"
The problem is that the tests requires some pre-setup (temp directories to be create, environment variables to set, etc).
So if I were working with a clean make, I would just modify the Makefile to this:
.PHONY test
test:
$(SHELL) -c
"source $(BUILD_PATH)/setup_tests.sh && \
$(CTEST) $(CTEST_FLAGS) --test-dir $(BUILD_PATH)"
But the Makefile is created by cmake and I have no idea where to define such changes.
The root CMakeLists.txt has a function call enable_tests(). The src/tests directory has its own CMakeLists.txt but it just defines a bunch of subdirectories with individual tests.
Could someone point me in the direction on how to customize the execution of specific target in the cmake? Or does the ctest has option to run a shell script before all the tests (The -S looks promising but it requires cmake's language script? It does not work with the .sh).
The typical CMake way would be to use test properties:
set_tests_properties(mytest PROPERTIES
ENVIRONMENT "VAR1=val1;VAR2=val2;VAR3=val3"
)
As with running a script to set the environment as opposed to the typical CMake way, you could simply set the command to run that script before the executable:
find_program(BASH_PROGRAM bash)
add_test(NAME mytest COMMAND
${BASH_PROGRAM} -c "source \"${CMAKE_BUILD_DIR}/setup_tests.sh\" && $<TARGET_FILE:myexec>"
)
The intended way to create this kind of logic would be to define a fixture test for the setup:
For convenience we're simply running the following cmake script allowing us to specify a message in addition to allowing us to specify, if the test should fail, but you could run your own bash script as test instead.
testscript.cmake
#[===[
Params:
MESSAGE: message to print
FAIL : fail the test?
]===]
if(FAIL)
message(FATAL_ERROR "${MESSAGE}")
else()
message(STATUS "${MESSAGE}")
endif()
CMakeLists.txt
enable_testing()
# the values of the FAIL parameter could be modified to to test different scenarios...
add_test(NAME Fixture COMMAND ${CMAKE_COMMAND} -D FAIL:BOOL=0 -D "MESSAGE:STRING=executing fixture" -P ${CMAKE_CURRENT_SOURCE_DIR}/testscript.cmake)
add_test(NAME Test COMMAND ${CMAKE_COMMAND} -D FAIL:BOOL=0 -D "MESSAGE:STRING=executing actual test" -P ${CMAKE_CURRENT_SOURCE_DIR}/testscript.cmake)
add_test(NAME Test2 COMMAND ${CMAKE_COMMAND} -D FAIL:BOOL=1 -D "MESSAGE:STRING=executing test without fixture" -P ${CMAKE_CURRENT_SOURCE_DIR}/testscript.cmake)
set_tests_properties(Fixture PROPERTIES FIXTURES_SETUP Setup)
set_tests_properties(Test PROPERTIES FIXTURES_REQUIRED Setup)
Now
ctest -R 'Test$' --verbose
Executes the Fixture test and if this test succeeds, the actual test requested (Test) is executed.
ctest -R Test2 --verbose
Just executes Test2.
You can add cleanup logic for tests in a similar manner.
some pre-setup (temp directories to be create, environment variables to set, etc).
Environment variables are set with set_tests_properties as in the other answer.
You can create a directory with FILE(MAKE_DIRECTORY from CMake
For an advanced journey, you may want to discover test fixtures, which are meant to "prepare" the environment (not environment variables) for tests, for example run a service that tests need.
how to customize the execution of specific target in the cmake?
add_test takes a command, you can run any command you want.
does the ctest has option to run a shell script before all the tests
Why all the tests? Just the tests that need to run that shell - fixtures sound like they are for that.
I'm working on a C++ project with CMake + clang. I would now like to integrate source-based coverage with my unit tests. When compiling with the right flags, raw coverage data is placed into files according to a pattern given by the LLVM_PROFILE_FILE environment variable. Since I'm using catch2 as a test framework I'm thus calling:
catch_discover_tests(
my_test
PROPERTIES ENVIRONMENT LLVM_PROFILE_FILE=coverage/my_test_%p.profraw
)
When running the test target, this will place a .profraw per test process in the coverage directory. I have also added a custom coverage target that merges these files into a .profdata file:
add_custom_command(
OUTPUT coverage/my_test.profdata
COMMAND llvm-profdata merge -sparse coverage/*.profraw -o coverage/my_test.profdata
)
add_custom_target(coverage DEPENDS coverage/my_test.profdata)
This works well enough. However, if I now run the test target again multiple times and forget to clear the coverage directory in between, running the coverage target will merge data from multiple test runs. That's not what I want so I would like to make sure that the coverage directory is always deleted before the tests run. But I'm not sure how to do this, I've tried:
add_custom_target(
clean_coverage_dir
COMMAND ${CMAKE_COMMAND} -E rm -rf coverage
)
add_dependencies(test clean_coverage_dir)
After catch_discover_tests but this results in:
Cannot add target-level dependencies to non-existent target "test".
What can I do? Should I maybe use a different approach altogether?
If anyone is interested, I've found a sort of obvious solution:
add_custom_target(
test_coverage
COMMAND ${CMAKE_COMMAND} -E rm -rf coverage &&
${CMAKE_CTEST_COMMAND} --force-new-ctest-process &&
llvm-profdata merge -sparse coverage/*.profraw -o coverage/my_test.profdata
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
)
I'm redefining my project's cmake configuration based on what I have learned from Daniel Pfeifer's “Effective CMake" talks, but I still cannot get my head around ctest.
Currently I have the following setup for my tests:
enable_testing()
find_program(MEMCHECK_COMMAND valgrind)
# executable
add_executable(myTest ${SRC_LIST})
target_link_libraries(myTest ${LIB_LIST})
# test
add_test(NAME myTest_test
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/myTest)
add_custom_target(myTest_test
COMMAND ctest -R myTest_test --output-on-failure
DEPENDS myTest)
# memcheck
add_test(NAME myTest_memcheck
COMMAND ${MEMCHECK_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/myTest)
add_custom_target(myTest_memcheck
COMMAND ctest -R myTest_memcheck --output-on-failure
DEPENDS ${TEST_NAME})
and I could run make myTest_test and make myTest_memcheck and know that I didn't break anything.
It pains me that I have to do this for every test executable (and project is big so I have dozens of them) and even extracted as a function it just feels wrong.
I have read ctest docs (https://gitlab.kitware.com/cmake/community/wikis/doc/ctest/Testing-With-CTest) and dashboards seems almost perfect to me - if I could just run ctest -R myTest -T test, ctest -R myTest -T memcheck and ctest -R myTest -T coverage I would be very happy :) (and even more happy if those commands will trigger build if needed).
The problem is that include(CTest) creates targets that I do not need (Continuous/Nightly dashboards with Start/Update/Configure/Submit steps). It will be used solely as experimental builds and executed by devs during coding. For CI I have Jenkins with it's own magic. I would like to end up with:
- Dashboard/Build
- Dashboard/Test
- Dashboard/MemCheck
- Dashboard/Coverage
What should I do? Should I create manually my own dashboard (if it is possible) or drop this idea and stay with my custom targets?
I would like to be able in a similar manner as I can run cmake like
cmake --build <bld_directory>
to run ctest like
ctest --build <bld_directory>
Obviously running ctest from the <bld-directory> will work,
but it would be nice if I can just tell ctest where to look for its configuration file and where the test executables are located.
From the documentation it is not very clear (or I might not have looked in the right place) if this is possible at all or not.
It would great if somebody could shed some light on if this is possible or not ?
Many thanks,
Jiri
Since CMake 3.20 ctest has the option --test-dir for exactly that.
--test-dir <dir> Specify the directory in which to look for tests.
For CMake older than 3.20:
I couldn't find the way to do it through ctest options, but it is doable using the rule make test which is linked to ctest.
In the Makefile generated by cmake in your build folder you can find the rule:
#Special rule for the target test
test:
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running tests..."
/usr/bin/ctest --force-new-ctest-process $(ARGS)
.PHONY : test
make provides the option that you want with -C /path/to/build_directory/, and you can add any ctest options with ARGS='your ctest options here'
For example, from any directory in your system you can write:
make test -C /path/to/build_folder ARGS='-R SpecificTestIWantToRun -VV'
or
cmake --build <bld_directory> --target test -- ARGS="<ctest_args>"
Another approach without make, is to use parenthesis in your terminal to create a subshell. This will execute the command without changing the folder of your current shell.
(cd $build_folder; ctest -V)
I'm using CMake to build my project. I have added a unit test binary which is using the Boost unit testing framework. This one binary contains all of the unit tests. I've added that binary to be run by CTest:
ADD_EXECUTABLE( tftest test-main.cpp )
ENABLE_TESTING()
ADD_TEST( UnitTests tftest)
But the build output in Visual Studio only shows the result of running CTest:
Start 1: UnitTests
1/1 Test #1: UnitTests ................***Failed 0.05 sec
0% tests passed, 1 tests failed out of 1
This is not very helpful, because I can't see which test failed. If I run ctest manually from the command line with --verbose I get the output from a Boost unit test which tells what actually failed:
1: Test command: tftest.exe
1: Test timeout computed to be: 9.99988e+006
1: Running 4 test cases...
1: test-main.cpp(20): error in "sanity_check3": check 1 == 2 failed
1:
1: *** 1 failure detected in test suite "Master Test Suite"
1/1 Test #1: UnitTests ................***Failed 0.00 sec
So, what do I need to change in the CMakeLists.txt to have CTest run with --verbose at all times? Is there a better way to use Boost unit tests with CMake/CTest?
You can use the ctest --output-on-failure option, or set the environment variable CTEST_OUTPUT_ON_FAILURE, which will show you any output from the test program whenever the test fails. One way to do this when using Makefiles and the command line would be as follows:
env CTEST_OUTPUT_ON_FAILURE=1 make check
This Stack Overflow question and answer shows how to set environment variables in Visual Studio.
You could call ctest directly, after cmaking and making your project.
ctest --verbose
There is a very simple solution (which for some reason is difficult to find via Google Search):
ctest --output-on-failure
If you use CMake with Visual Studio's open folder function you can add the
"ctestCommandArgs": "--output-on-failure"
setting to your build configuration.
You can check the Testing/Temporary subfolder. It is automatically created after running make test. This folder contains two files: LastTest.log and LastTestsFailed.log. LastTest.log contains desired output for run tests. LastTestFailed.log contains names of failed tests. So you can check them manually after executing make test.
The second way is to get ctest to show you the content of log files after running tests:
place in build dir (from which you run make test) file CTestCustom.ctest (you can do it with configure file command, for example) with following contents
CTEST_CUSTOM_POST_TEST("cat Testing/Temporary/LastTest.log")
Instead of cat you may use whatever Windows cmd command that does similar things.
run make test again and get profit!
additional info about customizing ctest you can find here. Just step to "Customizing cmake" section.
Good luck!
I had to add "check" target by myself. "make tests" does nothing by some reason. So what I did (as was suggest somewhere on stackoverflow) - I added this target manually. To get verbose output I just wrote it like:
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --verbose)
make check CTEST_OUTPUT_ON_FAILURE=TRUE
This makes test output more verbose:
make test ARGS="-V"
My approach is a combination of the answers from ony, from zbyszek, and from tarc. I use the ${CMAKE_COMMAND} variable (which is set to the absolute path to the invoked cmake executable) with the -E env CTEST_OUTPUT_ON_FAILURE=1 argument to invoke the actual ctest command using ${CMAKE_CTEST_COMMAND} -C $<CONFIG>. To help clarify what is going on, I start with three cmake -E echo commands to show the current working directory and the ctest command to be invoked. Here is how I call add_custom_target.
add_custom_target(check
${CMAKE_COMMAND} -E echo CWD=${CMAKE_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E echo CMD=${CMAKE_CTEST_COMMAND} -C $<CONFIG>
COMMAND ${CMAKE_COMMAND} -E echo ----------------------------------
COMMAND ${CMAKE_COMMAND} -E env CTEST_OUTPUT_ON_FAILURE=1
${CMAKE_CTEST_COMMAND} -C $<CONFIG>
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS ALL_BUILD
)
This plays nice with the MSVC IDE where any test errors are shown as clickable compilation errors. See cmake -E env for documentation of the cmake -E portable command line tool mode. I also add a dependency on ALL_BUILD so that all projects will be built before invoking the check target. (On Linux builds, one may need to replace ALL_BUILD with ALL; I have not tested this on Linux yet.)
For people using Visual Studio, here another variation (hack) on the theme:
cmake -E env CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target RUN_TESTS
ctest -VV or ctest --extra-verbose
From documentation:
Enable more verbose output from tests.
Test output is normally suppressed and only summary information is
displayed. This option will show even more test output.
There's now a CMake variable that allows you to modify the behaviour of make test. CMAKE_CTEST_ARGUMENTS lets you set a list of arguments to pass to ctest when run via make test.
So adding this to your CMake file:
set(CMAKE_CTEST_ARGUMENTS "--verbose")
Means CTest will always run verbose. Or for just the output of the failed tests, use:
set(CMAKE_CTEST_ARGUMENTS "--output-on-failure")
Edit:
As suggested by RobLoach, since it's a list of arguments, you'll want to append to the list instead.
list(APPEND CMAKE_CTEST_ARGUMENTS "--output-on-failure")
to show the result with XML file you have to execute the test with the following command
~$ ctest -T Test
and we found the result in the Testing/1234123432/test.xml
and other files are generated too in Testing Folder