179 votes

CMake : Structure de projet avec tests unitaires

J'essaie de structurer mon projet pour inclure les sources de production (en src ) et les tests (dans le sous-dossier test sous-dossier). J'utilise CMake pour le construire. Comme exemple minimal, j'ai les fichiers suivants :

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 - utilise sqr, n'a pas vraiment d'importance

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));
}

Quelques questions :

  1. Cette structure a-t-elle un sens ? Quelles sont les meilleures pratiques pour structurer ce code ? (Je viens du C# et de Java, et c'est plus facile dans un sens).
  2. Je n'aime pas le fait que je doive énumérer tous les fichiers de la base de données de l'entreprise. src dans le dossier test/CMakeLists.txt fichier. S'il s'agissait d'un projet de bibliothèque, je me contenterais de lier la bibliothèque. Existe-t-il un moyen d'éviter de lister tous les fichiers cpp de l'autre projet ?
  3. Quelles sont les lignes enable_testing() y add_test(MyTest test) à faire ? Je n'ai vu aucun effet. Comment puis-je exécuter les tests à partir de CMake (ou CTest) ?
  4. Jusqu'à présent, je n'ai fait qu'exécuter cmake . dans le dossier racine, mais cela a créé un désordre avec des fichiers temporaires partout. Comment puis-je obtenir les résultats de la compilation dans une structure raisonnable ?

159voto

Fraser Points 20579

Pour les questions 1 et 2, je recommanderais de créer une bibliothèque à partir de vos fichiers non-test à l'exclusion de main.cpp (dans ce cas juste src/sqr.cpp et src/sqr.h), et ainsi vous pourrez éviter de lister (et plus important de recompiler) toutes les sources deux fois.

Pour la question 3, ces commandes ajoutent un test appelé "MyTest" qui invoque votre exécutable "test" sans aucun argument. Cependant, puisque vous avez ajouté ces commandes à test/CMakeLists.txt et non pas à votre CMakeLists.txt de premier niveau, vous ne pouvez invoquer le test qu'à partir du sous-répertoire "test" de votre arbre de construction (essayez cd test && ctest -N ). Si vous voulez que le test soit exécutable depuis votre répertoire de construction de premier niveau, vous devez appeler add_test à partir du fichier CMakeLists.txt de premier niveau. Cela signifie également que vous devez utiliser la forme la plus verbeuse de la commande [add_test](http://www.cmake.org/cmake/help/v2.8.10/cmake.html#command:add_test "CMake v2.8.10 documentation for "add_test" command") puisque votre exe de test n'est pas défini dans le même CMakeLists.txt.

Dans votre cas, puisque vous exécutez cmake dans le dossier Root, votre arbre de construction et votre arbre des sources sont un et le même. Ceci est connu comme une construction in-source et n'est pas idéal, ce qui conduit à la question 4.

La méthode préférée pour générer l'arbre de compilation est de faire une compilation hors source, c'est-à-dire de créer un répertoire quelque part en dehors de votre arbre des sources et d'exécuter cmake à partir de là. Même en créant un répertoire "build" dans le Root de votre projet et en exécutant cmake .. fournit une structure propre qui n'interfère pas avec votre arbre des sources.

Un dernier point est d'éviter d'appeler les exécutables "test" (en respectant la casse). Pour savoir pourquoi, voir cette réponse .

Pour réaliser ces changements, je ferais ce qui suit :

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

63voto

Mathias Points 633

J'aime l'exemple de @Fraser mais j'utiliserais la commande add_test dans le test/CMakeLists.txt et utiliserais enable_testing avant add_subdirectory(test).

De cette façon, vous pouvez exécuter vos tests à partir du répertoire de construction de premier niveau tout en spécifiant vos tests dans le fichier test/CMakeLists.txt.

Le résultat ressemblerait à ceci (j'ai réutilisé l'exemple de @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)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X