CMake: Структура проекту з одиничними тестами


139

Я намагаюся структурувати свій проект, щоб він включав джерела виробництва (у srcпідпапках) та тести (у testпідпапках). Я використовую CMake для створення цього. Як мінімальний приклад у мене є такі файли:

CMakeLists.txt:

cmake_minimum_required (VERSION 2.8) 
project (TEST) 

add_subdirectory (src) 
add_subdirectory (test) 

src / CMakeLists.txt:

add_executable (demo main.cpp sqr.cpp) 

src / sqr.h

#ifndef SQR_H
#define SQR_H
double sqr(double);    
#endif // SQR_H

src / sqr.cpp

#include "sqr.h"
double sqr(double x) { return x*x; }

src / main.cpp - використовує sqr, насправді не має значення

test / CMakeLists.txt:

find_package(Boost COMPONENTS system filesystem unit_test_framework REQUIRED)

include_directories (${TEST_SOURCE_DIR}/src) 

ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK) 

add_executable (test test.cpp ${TEST_SOURCE_DIR}/src/sqr.cpp) 

target_link_libraries(test
                      ${Boost_FILESYSTEM_LIBRARY}
                      ${Boost_SYSTEM_LIBRARY}
                      ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                      )

enable_testing()
add_test(MyTest test)

test / test.cpp:

#define BOOST_TEST_MODULE SqrTests
#include <boost/test/unit_test.hpp>

#include "sqr.h"

BOOST_AUTO_TEST_CASE(FailTest)
{
    BOOST_CHECK_EQUAL(5, sqr(2));
}

BOOST_AUTO_TEST_CASE(PassTest)
{
    BOOST_CHECK_EQUAL(4, sqr(2));
}

Кілька питань:

  1. Чи має ця структура сенс? Які найкращі практики при структуруванні цього коду? (Я приїжджаю з C # і java, і там простіше у певному сенсі)
  2. Мені не подобається те, що мені доводиться перераховувати всі файли з srcпапки у test/CMakeLists.txtфайлі. Якби це був проект бібліотеки, я би просто зв’язав бібліотеку. Чи є спосіб уникнути перерахування всіх файлів cpp з іншого проекту?
  3. Які лінії enable_testing()та add_test(MyTest test)робити? Я не бачив жодного ефекту. Як я можу запустити тести з CMake (або CTest)?
  4. Поки я просто бігав cmake .у кореневу папку, але це створило безлад з тимчасовими файлами скрізь. Як я можу отримати результати компіляції у розумній структурі?

Я вважаю себе початківцем CMake, тому не знаю, що таке найкраща практика, але FWIW я б створив "sqr" бібліотеку *, від якої залежали і основні, і тестові. (* або його моральний еквівалент)
користувач786653

Відповіді:


125

Для питань 1 і 2 я рекомендую створити бібліотеку з ваших нетестових файлів, виключаючи main.cpp (у цьому випадку просто src / sqr.cpp та src / sqr.h), і тоді ви можете уникнути переліку (і що ще важливіше перекомпіляція) усі джерела двічі.

Для питання 3 ці команди додають тест під назвою "MyTest", який викликає ваш виконуваний "тест" без жодних аргументів. Однак, оскільки ви додали ці команди до тесту / CMakeLists.txt, а не до CMakeLists.txt верхнього рівня, ви можете викликати тест лише з підкаталогу "test" вашого дерева зборки (спробуйте cd test && ctest -N). Якщо ви хочете, щоб тест можна було виконати з каталогу збирання верхнього рівня, вам потрібно буде зателефонувати add_testз CMakeLists.txt вищого рівня. Це також означає, що вам доведеться використовувати більш детальну форму, add_testоскільки ваш тест exe не визначений у тому ж CMakeLists.txt

У вашому випадку, оскільки ви запускаєте cmake в кореневій папці, дерево складання та ваше джерело є одним і тим же. Це відоме як складання джерела і не є ідеальним, що призводить до питання 4.

Кращим методом для генерування дерева збірки є створення збірки з джерела, тобто створення каталогу десь за межами вашого вихідного дерева та виконання cmake звідти. Навіть створення каталогу "build" у корені вашого проекту та його виконання cmake ..забезпечить чисту структуру, яка не заважатиме вашому дереву джерел.

Одним із заключних пунктів є уникнення виклику виконуваних файлів "тестом" (залежно від регістру). З причин цього див. Цю відповідь .

Для досягнення цих змін я б зробив наступне:

CMakeLists.txt:

cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src) 
add_subdirectory (test)
enable_testing ()
add_test (NAME MyTest COMMAND Test)


src / CMakeLists.txt:

add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)


test / CMakeLists.txt:

find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src
                     ${Boost_INCLUDE_DIRS}
                     )
add_definitions (-DBOOST_TEST_DYN_LINK)
add_executable (Test test.cpp)
target_link_libraries (Test
                       Sqr
                       ${Boost_FILESYSTEM_LIBRARY}
                       ${Boost_SYSTEM_LIBRARY}
                       ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                       )

2
Щойно я помітив, що ви відповідно додали .h файли до файлів CMakeLists.txt. Це потрібно? А що буде, якщо я їх залишаю поза?
Grzenio

3
@Grzenio Це лише зручність - вони з'являються в IDE як MSVC як частина цілі, але в іншому випадку це не впливає.
Фрейзер

1
Де встановлено TEST_SOURCE_DIR?
aggsol

6
Він автоматично встановлюється CMake під час дзвінка project (TEST)- див. Cmake.org/cmake/help/v3.6/variable/PROJECT-NAME_SOURCE_DIR.html
Fraser

> вони з'являються в IDE як MSVC як частина цільової --- MSVC не підтримує маркувати каталог із заголовками як "включити каталог"?
isnullxbh

46

Мені подобається приклад @Fraser, але я б використовував команду add_test в тесті / CMakeLists.txt і використовував enable_testing перед add_subdirectory (тест).

Таким чином ви можете запустити свої тести з каталогу верхніх версій, вказуючи свої тести в тесті / CMakeLists.txt.

Результат виглядатиме приблизно так (я повторно використав приклад @Fraser):

CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src)

enable_testing ()
add_subdirectory (test)

src / CMakeLists.txt

add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)

test / CMakeLists.txt

find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src
                     ${Boost_INCLUDE_DIRS}
                     )
add_definitions (-DBOOST_TEST_DYN_LINK)
add_executable (Test test.cpp)
target_link_libraries (Test
                       Sqr
                       ${Boost_FILESYSTEM_LIBRARY}
                       ${Boost_SYSTEM_LIBRARY}
                       ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                       )
add_test (NAME MyTest COMMAND Test)

1
Дякую, я не показав жодних тестів ctest -Nдо того часу, поки не підкажемо підказку щодо ввімкнення тестування, перш ніж додавати субдір.
алаферг

@alaferg: інакше вони опиняться в тестовому піддіре всередині dir build.
Гауте

4
Я б хотів, щоб у CMake було щось схоже на структуру.
ruipacheco
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.