[unit-testing] GTest 및 CMake 작업을 시작하는 방법

나는 최근에 C ++ 프로젝트를 컴파일하기 위해 CMake를 사용하여 판매되었으며 이제 내 코드에 대한 일부 단위 테스트 작성을 시작하고 싶습니다. 이 문제를 해결하기 위해 Google 테스트 유틸리티를 사용하기로 결정했지만 시작하는 데 도움이 필요합니다.

저는 하루 종일 다양한 가이드와 예제를 읽고 있었는데 여기에는 Primer , IBM 소개 , SO에 대한 몇 가지 질문 ( 여기여기 ) 및 제가 놓친 다른 소스가 포함됩니다. 나는 거기에 많은 것이 있다는 것을 알고 있지만 어떻게 든 여전히 어려움을 겪고 있습니다.

현재 gtest를 컴파일 / 설치했고 작동하지 않는지 확인하기 위해 가장 기본적인 테스트를 구현하려고합니다. 유일한 소스 파일 (testgtest.cpp)은 이전의 대답 :

#include <iostream>

#include "gtest/gtest.h"

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

내 관련 CMakeLists.txt는 다음과 같습니다.

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
)

cpp 파일의 끝에 main을 제공하는 대신 gtest_main에 링크하기로 선택했습니다. 이렇게하면 여러 파일로 테스트를보다 쉽게 ​​확장 할 수 있습니다.

생성 된 .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 라이브러리에 성공적으로 연결되지 않았다는 것을 의미합니다. 디버그 라이브러리에 연결할 때 디버그 모드에서 빌드를 시도했는지 확인했습니다.

편집하다

좀 더 파고 들었을 때 내 문제는 내가 gtest를 구축하고있는 라이브러리 유형과 관련이 있다고 생각합니다. CMake로 gtest를 빌드 할 때BUILD_SHARED_LIBS 체크되지 않은 프로그램을 이러한 .lib 파일에 연결하면 위에서 언급 한 오류가 발생합니다. 그러나이 BUILD_SHARED_LIBS체크 되면 .lib 및 .dll 파일 세트를 생성합니다. 이제 이러한 .lib 파일에 연결하면 프로그램이 컴파일되지만 실행시 gtest.dll을 찾을 수 없다고 불평합니다.

a SHARED와 not SHARED라이브러리 의 차이점은 무엇이며 공유하지 않도록 선택하면 왜 작동하지 않습니까? 내 프로젝트에 대한 CMakeLists.txt에 누락 된 옵션이 있습니까?



답변

해결책은 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 )


답변

방금 테스트 한 완전한 작업 예제가 있습니다. 웹, 고정 tarball 또는 최신 하위 버전 디렉토리에서 직접 다운로드합니다.

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)


답변

두 세계의 장점을 모두 얻을 수 있습니다. 사용할 수 있습니다 ExternalProjectgtest 소스를 다운로드하고 사용하는 add_subdirectory()빌드에 추가 할 수 있습니다. 이것은 다음과 같은 장점이 있습니다.

  • gtest는 메인 빌드의 일부로 빌드되므로 동일한 컴파일러 플래그 등을 사용하므로 질문에 설명 된 것과 같은 문제를 방지합니다.
  • 자체 소스 트리에 gtest 소스를 추가 할 필요가 없습니다.

일반적인 방식으로 사용되는 ExternalProject는 구성시 (예 : CMake가 실행될 때) 다운로드 및 압축 해제를 수행하지 않지만 약간의 작업만으로 수행 할 수 있습니다. gtest뿐만 아니라 CMake를 빌드 시스템으로 사용하는 모든 외부 프로젝트에서 작동하는 일반화 된 구현도 포함하는이 작업을 수행하는 방법에 대한 블로그 게시물을 작성했습니다. 여기에서 찾을 수 있습니다.

업데이트 : 이 접근 방식은 이제 googletest 문서의 일부입니다 .


답변

대부분의 경우 테스트 바이너리와 Google 테스트 라이브러리 간의 컴파일러 옵션 차이는 이러한 오류에 대한 책임입니다. 그렇기 때문에 Google 테스트를 소스 형식으로 가져와 테스트와 함께 빌드하는 것이 좋습니다. CMake에서하는 것은 매우 쉽습니다. ADD_SUBDIRECTORYgtest 루트에 대한 경로로 호출 하기 만하면 거기에 정의 된 공용 라이브러리 대상 ( gtestgtest_main)을 사용할 수 있습니다 . 이 CMake 스레드 에 더 많은 배경 정보가 있습니다.googletestframework 그룹 에 있습니다.

BUILD_SHARED_LIBS옵션은 현재 Windows에서만 유효합니다. CMake에서 빌드 할 라이브러리 유형을 지정합니다. 로 설정하면 ONCMake가 정적 라이브러리가 아닌 DLL로 빌드합니다. 이 경우 -DGTEST_LINKED_AS_SHARED_LIBRARY = 1로 테스트를 빌드하고 CMake에서 생성 한 DLL 파일을 테스트 바이너리가있는 디렉터리에 복사해야합니다 (CMake는 기본적으로 별도의 출력 디렉터리에 배치). 정적 lib의 gtest가 작동하지 않는 한 해당 옵션을 설정하지 않는 것이 더 쉽습니다.


답변

좀 더 파고 들었을 때 내 문제는 내가 gtest를 구축하고있는 라이브러리 유형과 관련이 있다고 생각합니다. CMake로 gtest를 빌드 할 때 BUILD_SHARED_LIBS가 선택되어 있지 않고 프로그램을 이러한 .lib 파일에 연결하면 위에서 언급 한 오류가 발생합니다. 그러나 BUILD_SHARED_LIBS가 선택되면 .lib 및 .dll 파일 세트를 생성합니다. 이제 이러한 .lib 파일에 연결하면 프로그램이 컴파일되지만 실행시 gtest.dll을 찾을 수 없다고 불평합니다.

gtest를 공유 라이브러리로 사용하려면 프로젝트의 컴파일러 정의에 -DGTEST_LINKED_AS_SHARED_LIBRARY = 1을 추가해야하기 때문입니다.

사용자가 본 오류를 제거하기 위해 gtest_force_shared_crt 옵션을 사용하여 컴파일 한 경우 정적 라이브러리를 사용할 수도 있습니다.

나는 도서관을 좋아하지만 그것을 프로젝트에 추가하는 것은 진짜 고통입니다. 그리고 gtest cmake 파일을 파고 (및 해킹)하지 않는 한 올바르게 수행 할 기회가 없습니다. 부끄러움. 특히 나는 gtest를 소스로 추가하는 아이디어가 마음에 들지 않습니다. 🙂


답변

OP는 Windows를 사용하고 있으며 오늘날 GTest를 사용하는 훨씬 쉬운 방법은 vcpkg + cmake를 사용하는 것입니다.


https://github.com/microsoft/vcpkg 에 따라 vcpkg를 설치 vcpkg하고 cmd 줄에서 실행할 수 있는지 확인합니다 . vcpkg 설치 폴더를 기록해 둡니다. C:\bin\programs\vcpkg.

다음을 사용하여 gtest 설치 vcpkg install gtest: GTest를 다운로드, 컴파일 및 설치합니다.

아래와 같이 CmakeLists.txt를 사용하십시오 . 폴더를 포함하는 대신 대상 을 사용할 수 있습니다 .

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)

cmake 실행 : (필요한 경우 vcpkg 폴더를 편집하고 vcpkg.cmake 도구 모음 파일의 경로가 올바른지 확인)

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

사용하여 빌드 cmake --build build평소 . vcpkg는 또한 필요한 gtest (d) .dll / gtest (d) _main.dll을 설치 폴더에서 Debug / Release 폴더로 복사합니다.

테스트합니다 cd build & ctest.


답변

귀하와 VladLosevs의 솔루션은 아마도 저보다 낫습니다. 그러나 무차별 대입 솔루션을 원한다면 다음을 시도하십시오.

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)