Как начать работу с GTest и CMake


недавно я был продан с помощью CMake для компиляции моих проектов на C++, и теперь хотел бы начать писать некоторые модульные тесты для моего кода. Я решил использовать утилиту Google Test, чтобы помочь с этим, но требуется некоторая помощь в начале работы.

весь день я читал различные руководства и примеры включают в себя букварь, an введение в IBM и некоторые вопросы по SO (здесь и здесь), а также другие источники я потерял из виду. Я понимаю, что есть много там, но почему-то у меня все еще возникают трудности.

в настоящее время я пытаюсь реализовать самый простой тест, чтобы подтвердить, что я скомпилировал/установил gtest правильно, и он не работает. Единственный исходный файл (testgtest.cpp) берется почти точно из этой предыдущий ответ:

#include <iostream>

#include "gtest/gtest.h"

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

и мои связанные CMakeLists.текст выглядит следующим образом:

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
)

обратите внимание, что я выбрал ссылку против gtest_main вместо предоставления основного в конце файла cpp, поскольку я считаю, что это позволит мне легче масштабировать тестирование до нескольких файлов.

при создании генерируется .sln файл (в Visual C++ 2010 Express) я к сожалению получаю длинный список ошибок вида

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)

что, я думаю, означает, что я не успешно связываюсь с библиотеками gtest. Я убедился, что при связывании с библиотеками отладки я попытался построить режим отладки.

EDIT

сделав еще несколько раскопок, я думаю, что моя проблема связана с типом библиотеки, в которую я создаю gtest. При построении gtest с CMake, если BUILD_SHARED_LIBS не проверяется, и я связываю свою программу с ними .lib файлы я получаю ошибки, упомянутые выше. Однако, если BUILD_SHARED_LIBS проверяется, то я произвожу набор .lib и .DLL-файл. Когда теперь связывание против них .lib файлы программа компилирует, но при запуске жалуется, что она не могу найти gtest.файл DLL.

в чем разница между a SHARED и SHARED библиотека, и если я выбираю не общий, почему это не работает? Есть ли вариант в CMakeLists.txt для моего проекта, который мне не хватает?

7 92

7 ответов:

решение включало в себя размещение исходного каталога gtest в качестве подкаталога вашего проекта. Я включил рабочие CMakeLists.txt ниже, если это кому-то полезно.

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 )

вот полный рабочий пример, который я только что протестировал. Он загружает непосредственно из интернета, либо фиксированный тарбол, либо последний каталог subversion.

cmake_minimum_required (VERSION 3.1)

project (registerer)

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

include(ExternalProject)
ExternalProject_Add(gtest
  URL https://googletest.googlecode.com/files/gtest-1.7.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)

скорее всего, в таких ошибках виновата разница в параметрах компилятора между вашим тестовым двоичным файлом и тестовой библиотекой Google. Вот почему рекомендуется ввести Google Test в исходную форму и построить его вместе с вашими тестами. Это очень легко сделать в CMake. Вы просто вызываете ADD_SUBDIRECTORY с путем к корню gtest, а затем вы можете использовать цели публичной библиотеки (gtest и gtest_main) определено есть. Существует больше справочной информации в этом CMake thread в группа googletestframework.

[редактирование] Элемент BUILD_SHARED_LIBS опция действует только на Windows на данный момент. Он определяет тип библиотек, которые вы хотите построить CMake. Если вы установите его в ON, CMake будет строить их как DLL, а не статические библиотеки. В этом случае вы должны построить свои тесты с-DGTEST_LINKED_AS_SHARED_LIBRARY=1 и скопировать DLL-файлы, созданные CMake, в каталог с вашим тестовым двоичным файлом (CMake помещает их в отдельный выходной каталог по умолчанию). Если gtest в статической lib не работает для вас, проще не устанавливать эту опцию.

Вы можете получить лучшее из обоих миров. Можно использовать ExternalProject чтобы загрузить источник gtest, а затем использовать add_subdirectory(), чтобы добавить его в сборку. Это имеет следующие преимущества:

  • gtest построен как часть вашей основной сборки, поэтому он использует те же флаги компилятора и т. д. и, следовательно, избегает проблем, подобных тем, которые описаны в вопросе.
  • нет необходимости добавлять источники gtest в свое собственное дерево источников.

используется в обычном режиме, ExternalProject не будет выполнять загрузку и распаковку во время настройки (т. е. при запуске CMake), но вы можете заставить его сделать это с помощью всего лишь небольшой работы. Я написал сообщение в блоге о том, как это сделать, которое также включает обобщенную реализацию, которая работает для любого внешнего проекта, который использует CMake в качестве своей системы сборки, а не только gtest. Вы можете найти их здесь:

обновление: этот подход теперь тоже часть документации googletest.

сделав еще несколько раскопок, я думаю, что моя проблема связана с типом библиотеки, в которую я создаю gtest. При построении gtest с CMake, если BUILD_SHARED_LIBS не проверяется, и я связываю свою программу с ними .lib файлы я получаю ошибки, упомянутые выше. Однако, если BUILD_SHARED_LIBS проверяется, то я создаю набор .lib и .DLL-файл. Когда теперь связывание против них .lib-файлы программа компилируется, но при запуске жалуется, что не может найти gtest.файл DLL.

это потому, что вы должны добавить-DGTEST_LINKED_AS_SHARED_LIBRARY=1 к определениям компилятора в вашем проекте, если вы хотите использовать gtest в качестве общей библиотеки.

вы также можете использовать статические библиотеки, если вы скомпилировали его с опцией gtest_force_shared_crt для устранения ошибок, которые вы видели.

Мне нравится библиотека, но добавление ее в проект-это настоящая боль. И у вас нет никаких шансов сделать это правильно, если вы не копать (и взломать) в файлы gtest cmake. Стыд. В частности, мне не нравится идея добавления gtest в качестве источника. :)

ваши и Владлосевских решения, вероятно, лучше, чем мои. Если вы хотите решение грубой силы, однако, попробуйте это:

SET(CMAKE_EXE_LINKER_FLAGS /NODEFAULTLIB:\"msvcprtd.lib;MSVCRTD.lib\")

FOREACH(flag_var
    CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
    CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
    if(${flag_var} MATCHES "/MD")
        string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
    endif(${flag_var} MATCHES "/MD")
ENDFOREACH(flag_var)

самые простые CMakeLists.txt я дистиллировал из ответов в этой теме и некоторые проб и ошибок:

project(test CXX C)
cmake_minimum_required(VERSION 2.6.2)

#include folder contains current project's header filed
include_directories("include")

#test folder contains test files
set (PROJECT_SOURCE_DIR test) 
add_executable(hex2base64 ${PROJECT_SOURCE_DIR}/hex2base64.cpp)

# Link test executable against gtest nothing else required
target_link_libraries(hex2base64 gtest pthread)

Gtest уже должен быть установлен в вашей системе.