151 votes

Comment commencer à travailler avec GTest et CMake

J'ai récemment été convaincu d'utiliser CMake pour compiler mes projets C++, et j'aimerais maintenant commencer à écrire des tests unitaires pour mon code. J'ai décidé d'utiliser l'utilitaire Google Test pour m'aider dans cette tâche, mais j'ai besoin d'aide pour commencer.

Toute la journée, j'ai lu différents guides, parmi lesquels le L'abécédaire , un introduction chez IBM et quelques questions sur le SO ( ici y ici ) ainsi que d'autres sources dont j'ai perdu la trace. Je sais qu'il y a beaucoup de choses à faire, mais j'ai toujours des difficultés.

J'essaie actuellement de mettre en place le test le plus basique, pour confirmer que j'ai bien compilé/installé gtest et qu'il ne fonctionne pas. Le seul fichier source (testgtest.cpp) est tiré presque exactement de cette réponse précédente :

#include <iostream>

#include "gtest/gtest.h"

TEST(sample_test_case, sample_test)
{
    EXPECT_EQ(1, 1);
}

et mon fichier CMakeLists.txt associé est le suivant :

cmake_minimum_required(VERSION 2.6)
project(basic_test)

# Setup testing
enable_testing()
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIR})

# Add test cpp file
add_executable(runUnitTests
    testgtest.cpp
)

# Link test executable against gtest & gtest_main
target_link_libraries(runUnitTests ${GTEST_LIBRARY_DEBUG} ${GTEST_MAIN_LIBRARY_DEBUG})

add_test(
    NAME runUnitTests
    COMMAND runUnitTests
)

Notez que j'ai choisi de faire un lien avec gtest_main au lieu de fournir le main à la fin du fichier cpp, car je pense que cela me permettra d'étendre plus facilement les tests à plusieurs fichiers.

Lors de la construction du fichier .sln généré (dans Visual C++ 2010 Express), j'obtiens malheureusement une longue liste d'erreurs de la forme suivante

2>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: virtual __thiscall std::basic_iostream<char,struct std::char_traits<char> >::~basic_iostream<char,struct std::char_traits<char> >(void)" (??1?$basic_iostream@DU?$char_traits@D@std@@@std@@UAE@XZ) already defined in gtestd.lib(gtest-all.obj)

ce qui signifie, je pense, que je ne réussis pas à lier les bibliothèques gtest. Je me suis assuré que lors de l'édition de liens avec les bibliothèques de débogage, j'ai essayé de construire en mode débogage.

EDIT

Après avoir creusé un peu plus, je pense que mon problème est lié au type de bibliothèque dans laquelle je construis gtest. Lorsque je compile gtest avec CMake, si BUILD_SHARED_LIBS n'est pas coché, et si j'associe mon programme à ces fichiers .lib, j'obtiens les erreurs mentionnées ci-dessus. Cependant, si l'option BUILD_SHARED_LIBS est coché, je produis un ensemble de fichiers .lib et .dll. Lors de l'édition de liens avec ces fichiers .lib, le programme se compile, mais lorsqu'il est exécuté, il se plaint de ne pas trouver gtest.dll.

Quelles sont les différences entre un SHARED et un pas SHARED et si je choisis de ne pas partager, pourquoi cela ne fonctionne-t-il pas ? Est-ce qu'il y a une option dans le CMakeLists.txt pour mon projet que j'ai manqué ?

4 votes

Vous pouvez éviter d'inclure les sources GTest dans les vôtres en utilisant ExternalProject_Add plutôt que add_subdirectory . Voir cette réponse pour plus de détails.

0 votes

Pourquoi avons-nous accès à ${gtest_SOURCE_DIR} dans l'exemple de solution ci-dessus ? Comment/où cette variable est-elle déclarée ?

0 votes

Oh c'est déclaré dans gtest-1.6.0/CMakeLists.txt : "project(gtest CXX C)" qui rend les variables gtest_SOURCE_DIR et gtest_BINARY_DIR disponibles.

95voto

Chris Points 2473

La solution consiste à placer le répertoire source de gtest dans un sous-répertoire de votre projet. J'ai inclus le fichier CMakeLists.txt ci-dessous si cela peut aider quelqu'un.

cmake_minimum_required(VERSION 2.6)
project(basic_test)

################################
# GTest
################################
ADD_SUBDIRECTORY (gtest-1.6.0)
enable_testing()
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})

################################
# Unit Tests
################################
# Add test cpp file
add_executable( runUnitTests testgtest.cpp )
# Link test executable against gtest & gtest_main
target_link_libraries(runUnitTests gtest gtest_main)
add_test( runUnitTests runUnitTests )

3 votes

Je ne suis pas sûr de ce que fait la fonction add_test(), mais elle ne semble pas entraîner l'exécution du binaire de test... Ai-je raté quelque chose ?

4 votes

Je ne veux pas revenir sur un sujet déjà évoqué, mais j'ai pensé qu'il valait la peine d'en parler à nouveau. Le commentaire de Fraser ci-dessus soulève un point très important : "Vous pouvez éviter d'inclure les sources de GTest dans les vôtres en utilisant ExternalProject_Add plutôt que add_subdirectory." Voir la réponse et les commentaires de Fraser pour plus de détails ici : stackoverflow.com/a/9695234/1735836

2 votes

Dans mon cas, j'ai également dû ajouter pthread aux bibliothèques liées, en remplaçant l'avant-dernière ligne par target_link_libraries(runUnitTests gtest gtest_main pthread)

50voto

user1427799 Points 809

Voici un exemple complet que je viens de tester. Il télécharge directement depuis le web, soit une archive fixe, soit le dernier répertoire de subversion.

cmake_minimum_required (VERSION 3.1)

project (registerer)

##################################
# Download and install GoogleTest

include(ExternalProject)
ExternalProject_Add(gtest
  URL https://github.com/google/googletest/archive/release-1.8.0.zip
  # Comment above line, and uncomment line below to use subversion.
  # SVN_REPOSITORY http://googletest.googlecode.com/svn/trunk/ 
  # Uncomment line below to freeze a revision (here the one for 1.7.0)
  # SVN_REVISION -r700

  PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gtest
  INSTALL_COMMAND ""
)
ExternalProject_Get_Property(gtest source_dir binary_dir)

################
# Define a test
add_executable(registerer_test registerer_test.cc)

######################################
# Configure the test to use GoogleTest
#
# If used often, could be made a macro.

add_dependencies(registerer_test gtest)
include_directories(${source_dir}/include)
target_link_libraries(registerer_test ${binary_dir}/libgtest.a)
target_link_libraries(registerer_test ${binary_dir}/libgtest_main.a)

##################################
# Just make the test runnable with
#   $ make test

enable_testing()
add_test(NAME    registerer_test 
         COMMAND registerer_test)

18voto

Craig Scott Points 3981

Vous pouvez obtenir le meilleur des deux mondes. Il est possible d'utiliser ExternalProject pour télécharger les sources de gtest et utiliser ensuite add_subdirectory() pour l'ajouter à votre construction. Cela présente les avantages suivants :

  • gtest est construit dans le cadre de votre construction principale, il utilise donc les mêmes drapeaux de compilation, etc. et évite ainsi des problèmes tels que ceux décrits dans la question.
  • Il n'est pas nécessaire d'ajouter les sources de gtest à votre propre arbre des sources.

Utilisé de manière normale, ExternalProject ne fera pas le téléchargement et le déballage au moment de la configuration (c'est-à-dire lorsque CMake est lancé), mais vous pouvez le faire avec juste un peu de travail. J'ai écrit un article de blog sur la façon de procéder qui inclut également une implémentation généralisée qui fonctionne pour n'importe quel projet externe qui utilise CMake comme système de construction, pas seulement gtest. Vous pouvez les trouver ici :

Mise à jour : Cette approche est désormais également partie de la documentation de googletest .

14voto

VladLosev Points 2097

Il est fort probable que la différence d'options de compilation entre votre binaire de test et la bibliothèque Google Test soit à l'origine de ces erreurs. C'est pourquoi il est recommandé d'intégrer Google Test sous forme de source et de le compiler en même temps que vos tests. C'est très facile à faire avec CMake. Il suffit d'invoquer ADD_SUBDIRECTORY avec le chemin d'accès à la racine de gtest, puis vous pouvez utiliser les cibles de la bibliothèque publique ( gtest y gtest_main ) qui y est définie. Vous trouverez plus d'informations sur le contexte dans le document suivant Fil CMake dans le groupe googletestframework.

[modifier] Le BUILD_SHARED_LIBS n'est efficace que sous Windows pour l'instant. Elle spécifie le type de bibliothèques que vous voulez que CMake construise. Si vous la mettez à ON CMake les construira comme des DLL et non comme des librairies statiques. Dans ce cas, vous devez compiler vos tests avec -DGTEST_LINKED_AS_SHARED_LIBRARY=1 et copier les fichiers DLL produits par CMake dans le répertoire contenant votre binaire de test (CMake les place par défaut dans un répertoire de sortie séparé). A moins que gtest in static lib ne fonctionne pas pour vous, il est plus facile de ne pas mettre cette option.

1 votes

Merci beaucoup, je n'avais pas réalisé qu'on pouvait construire des projets complètement séparés dans les mêmes CMakeLists comme ça. Je peux maintenant affirmer que EXPECT_EQ(1.0 == 1.0) passe et que EXPECT_EQ(0.0 == 1.0) échoue. Il est maintenant temps de faire des tests plus réels...

4voto

Daniele Points 1938

L'OP utilise Windows, et un moyen beaucoup plus facile d'utiliser GTest aujourd'hui est avec vcpkg +cmake.


Installer vcpkg comme suit https://github.com/microsoft/vcpkg et assurez-vous que vous pouvez exécuter vcpkg à partir de la ligne cmd. Notez le dossier d'installation de vcpkg, par exemple. C:\bin\programs\vcpkg .

Installer gtest en utilisant vcpkg install gtest : ceci téléchargera, compilera et installera GTest.

Utilisez un fichier CmakeLists.txt comme ci-dessous : notez que nous pouvons utiliser cibles au lieu d'inclure des dossiers.

cmake_minimum_required(VERSION 3.15)
project(sample CXX)
enable_testing()
find_package(GTest REQUIRED)
add_executable(test1 test.cpp source.cpp)
target_link_libraries(test1 GTest::GTest GTest::Main)
add_test(test-1 test1)

Exécutez cmake avec : (modifiez le dossier vcpkg si nécessaire, et assurez-vous que le chemin d'accès au fichier vcpkg.cmake toolchain est correct)

cmake -B build -DCMAKE_TOOLCHAIN_FILE=C:\bin\programs\vcpkg\scripts\buildsystems\vcpkg.cmake

et construire en utilisant cmake --build build comme d'habitude. Notez que vcpkg copiera également les fichiers gtest(d).dll/gtest(d)_main.dll du dossier d'installation vers les dossiers Debug/Release.

Test avec cd build & ctest .

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