CMakeMiddleCoding
Как включить и настроить CTest (тестирование CMake) в проекте?
CTest включается командой enable_testing() в CMakeLists.txt, тесты добавляются через add_test(). Запускается командой ctest из build-директории с флагами -V для вывода и --output-on-failure для CI.
Настройка CTest в CMake-проекте
CTest — компонент CMake для запуска тестов. Он не привязан к конкретному фреймворку: можно тестировать через Google Test, Catch2, Boost.Test или любой исполняемый файл, возвращающий ненулевой код при ошибке.
Минимальная настройка
cmake_minimum_required(VERSION 3.20)
project(MyApp CXX)
enable_testing() # ОБЯЗАТЕЛЬНО — активирует CTest
add_executable(my_app src/main.cpp)
# Добавляем тест: имя + команда
add_test(NAME SmokeTest COMMAND my_app --selftest)
Интеграция с Google Test
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/v1.14.0.zip
)
FetchContent_MakeAvailable(googletest)
add_executable(unit_tests
tests/test_math.cpp
tests/test_parser.cpp
)
target_link_libraries(unit_tests PRIVATE GTest::gtest_main)
# Автоматически регистрирует все TEST() как CTest-тесты
include(GoogleTest)
gtest_discover_tests(unit_tests)
Параметры add_test
# Рабочая директория
add_test(
NAME IntegrationTest
COMMAND integration_runner
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/testdata
)
# Передача переменных окружения
set_tests_properties(IntegrationTest PROPERTIES
ENVIRONMENT "DB_URL=sqlite::memory:;LOG_LEVEL=debug"
TIMEOUT 30 # секунды
LABELS "slow" # для фильтрации
)
Запуск тестов
# Сборка и запуск
cmake -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build
cd build
ctest # тихий режим
ctest -V # verbose: весь stdout тестов
ctest --output-on-failure # показывать вывод только упавших (идеал для CI)
ctest -R "Unit" # только тесты, чьё имя содержит "Unit"
ctest -L "slow" # тесты с лейблом slow
ctest -j4 # параллельный запуск (4 потока)
ctest --repeat until-fail:5 # повторять до первого падения
Интеграция с CI (GitHub Actions)
- name: Configure
run: cmake -B build -DCMAKE_BUILD_TYPE=Release
- name: Build
run: cmake --build build --parallel
- name: Test
working-directory: build
run: ctest --output-on-failure --parallel 4
CTestTestfile и CDash
CTest умеет отправлять результаты на CDash-сервер через ctest -D Experimental или ctest -D Continuous. Настройка хоста — в файле CTestConfig.cmake:
set(CTEST_PROJECT_NAME "MyApp")
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
set(CTEST_DROP_METHOD "https")
set(CTEST_DROP_SITE "my-cdash.example.com")
set(CTEST_DROP_LOCATION "/submit.php?project=MyApp")
Подводные камни
enable_testing()должен быть вызван в корневомCMakeLists.txt, а не только в поддиректории — иначеctestне найдёт тесты изadd_subdirectory().gtest_discover_tests()запускает тестовый бинарник при конфигурации (cmake-фазе), поэтому он должен быть собран до вызова — используйтеgtest_add_tests()как альтернативу если это проблема.- Тест считается упавшим, если процесс завершился с ненулевым кодом — убедитесь, что ваш runner правильно пробрасывает exit code.
- По умолчанию
ctestне пересобирает проект — запускайтеcmake --buildпередctestявно или используйтеcmake --build build --target test. - Параллельный запуск (
-j) опасен, если тесты пишут в одни и те же файлы или порты — явно задавайтеRESOURCE_LOCKчерезset_tests_properties. - TIMEOUT по умолчанию не установлен — зависший тест блокирует весь CI. Всегда устанавливайте разумный таймаут.
Common mistakes
- Объяснять CTest только по синтаксису, без жизненного цикла и стоимости.
- Игнорировать ошибки, null/empty состояния, порядок инициализации или режим сборки.
- Давать пример, который работает в демо, но ломается при изменении владельца ресурса.
- Трактовать CMake как shell-скрипт вместо описания графа таргетов.
What the interviewer is testing
- Кандидат формулирует точную модель для CTest, а не только определение.
- Пример компилируем, безопасен по lifetime и соответствует версии технологии.
- Названы trade-off, ограничения и диагностируемые симптомы ошибки.
- Разделяет configure/generate/build и использует target-based подход.