How to modify CMakeLists.txt to customize test target

Viewed 66

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).

3 Answers

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.

Related