CMake: struktura projektu z testami jednostkowymi
Próbuję uporządkować swój projekt tak, aby zawierał źródła produkcji (w podfolderze src
) i testy (w podfolderze test
). Używam CMake do zbudowania tego. Jako minimalny przykład mam następujące pliki:
Cmakeliści.txt:
cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src)
add_subdirectory (test)
Src / Cmakelisty.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-używa sqr, nie do końca Materia
Test / Cmakelisty.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));
}
Kilka pytań:
-
Czy ta struktura ma sens? Jakie są najlepsze praktyki podczas strukturyzacji tego kodu? Nie jest to jednak żaden problem, ponieważ nie jest to możliwe.]}
- nie podoba mi się to, że muszę wypisać wszystkie pliki z folderu
src
w plikutest/CMakeLists.txt
. Gdyby to był projekt biblioteczny, po prostu połączyłbym bibliotekę. Czy istnieje sposób, aby uniknąć wymieniania wszystkich pliki cpp z innego projektu? - co robią linie
enable_testing()
iadd_test(MyTest test)
? Nie widzę żadnego efektu. Jak mogę uruchomić testy z CMake (lub CTest)? - do tej pory pobiegłem
cmake .
w folderze głównym, ale to spowodowało bałagan z plikami tymczasowymi wszędzie. Jak Mogę uzyskać wyniki kompilacji w rozsądnej strukturze?
2 answers
W przypadku pytań 1 i 2, polecam stworzenie biblioteki z plików nie testowych z wyłączeniem main.cpp (w tym przypadku tylko src/SQR.cpp i src/SQR.h), a następnie można uniknąć dwukrotnego wypisywania (i co ważniejsze ponownej kompilacji) wszystkich źródeł.
Dla pytania 3, te polecenia dodają test o nazwie "MyTest", który wywołuje Twój plik wykonywalny "test" bez żadnych argumentów. Jednak, ponieważ dodałeś te polecenia do test/CMakeLists.txt, a nie twoje topowe Cmakelisty.txt, można wywoływać tylko test z podkatalogu "test" w drzewie kompilacji (try cd test && ctest -N
). Jeśli chcesz, aby test był uruchamiany z katalogu najwyższego poziomu, musisz wywołać add_test
z najwyższego poziomu CMakeLists.txt. Oznacza to również, że musisz użyć bardziej wyrazistej formy add_test
ponieważ twój test exe nie jest zdefiniowany w tych samych Cmakelistach.txt
W Twoim przypadku, ponieważ używasz cmake w folderze głównym, twoje drzewo kompilacji i drzewo źródłowe są jednym i tym samym. Jest to znane jako in-source build i nie jest idealny, co prowadzi do pytania 4.
Preferowaną metodą generowania drzewa kompilacji jest wykonanie kompilacji poza źródłem, tzn. utworzenie katalogu gdzieś poza drzewem źródłowym i stamtąd wykonanie cmake. Nawet utworzenie katalogu" build " w katalogu głównym projektu i wykonanie cmake ..
zapewniłoby czystą strukturę, która nie będzie kolidować z Twoim drzewem źródłowym.
Ostatnim punktem jest uniknięcie wywoływania plików wykonywalnych "test" (rozróżnianie wielkości liter). Na powody dlaczego, zobacz ta odpowiedź .
Aby osiągnąć te zmiany, wykonałbym następujące czynności:
Cmakeliści.txt:
cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src)
add_subdirectory (test)
enable_testing ()
add_test (NAME MyTest COMMAND Test)
src / Cmakeliści.txt:
add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)
test / Cmakelisty.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}
)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:26
Podoba mi się przykład @Fraser, ale użyłbym polecenia add_test w teście/CMakeLists.txt i użyj enable_testing przed add_subdirectory (test).
W ten sposób możesz uruchamiać swoje testy z katalogu kompilacji najwyższego poziomu, określając swoje testy w test/CMakeLists.txt.
Wynik wyglądałby tak (użyłem ponownie przykładu @Fraser):
Cmakeliści.txt
cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src)
enable_testing ()
add_subdirectory (test)
Src / Cmakelisty.txt
add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)
Test / Cmakelisty.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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-09 02:45:16