unit testing - google - Cómo comenzar a trabajar con GTest y CMake
google test (7)
Recientemente me vendieron usando CMake para compilar mis proyectos en C ++, y ahora me gustaría comenzar a escribir algunas pruebas de unidad para mi código. He decidido utilizar la herramienta de prueba de Google para ayudar con esto, pero necesito ayuda para comenzar.
Todo el día he estado leyendo varias guías y ejemplos incluyen el Primer , una introducción en IBM y algunas preguntas sobre SO ( here y here ), así como otras fuentes de las que he perdido la pista. Me doy cuenta de que hay mucho por ahí, pero de alguna manera todavía estoy teniendo dificultades.
Actualmente estoy intentando implementar la prueba más básica, para confirmar que he compilado / instalado gtest correctamente y que no está funcionando. El único archivo fuente (testgtest.cpp) se toma casi exactamente de here respuesta anterior:
#include <iostream>
#include "gtest/gtest.h"
TEST(sample_test_case, sample_test)
{
EXPECT_EQ(1, 1);
}
y mi CMakeLists.txt asociado es el siguiente:
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
)
Tenga en cuenta que he elegido vincular con gtest_main en lugar de proporcionar el principal al final del archivo cpp, ya que creo que esto me permitirá escalar las pruebas más fácilmente a varios archivos.
Al generar el archivo .sln generado (en Visual C ++ 2010 Express) desafortunadamente recibí una larga lista de errores del formulario
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)
lo cual creo que significa que no estoy logrando un enlace a las bibliotecas de gtest. Me he asegurado de que al vincular con las bibliotecas de depuración, intenté construir en modo de depuración.
EDITAR
Después de haber investigado un poco más, creo que mi problema tiene que ver con el tipo de biblioteca en la que estoy creando gtest. Al compilar gtest con CMake, si BUILD_SHARED_LIBS
está marcado, y vinculo mi programa con estos archivos .lib, recibo los errores mencionados anteriormente. Sin embargo, si BUILD_SHARED_LIBS
está marcado, entonces BUILD_SHARED_LIBS
un conjunto de archivos .lib y .dll. Cuando ahora se vinculan con estos archivos .lib, el programa se compila, pero cuando se ejecuta se queja de que no puede encontrar gtest.dll.
¿Cuáles son las diferencias entre una biblioteca SHARED
y no SHARED
, y si elijo no compartir, ¿por qué no funciona? ¿Existe una opción en el CMakeLists.txt para mi proyecto que me falta?
Después de haber investigado un poco más, creo que mi problema tiene que ver con el tipo de biblioteca en la que estoy creando gtest. Al compilar gtest con CMake, si BUILD_SHARED_LIBS no está marcado, y vinculo mi programa con estos archivos .lib, recibo los errores mencionados anteriormente. Sin embargo, si BUILD_SHARED_LIBS está marcado, entonces produzco un conjunto de archivos .lib y .dll. Cuando ahora se vinculan con estos archivos .lib, el programa se compila, pero cuando se ejecuta se queja de que no puede encontrar gtest.dll.
Esto se debe a que debe agregar -DGTEST_LINKED_AS_SHARED_LIBRARY = 1 a las definiciones del compilador en su proyecto si desea usar gtest como una biblioteca compartida.
También puede usar las bibliotecas estáticas, siempre que las haya compilado con la opción gtest_force_shared_crt para eliminar los errores que haya visto.
Me gusta la biblioteca pero agregarla al proyecto es un verdadero dolor. Y no tienes posibilidad de hacerlo bien a menos que excaves (y piratees) en los archivos de ctest gtest. Vergüenza. En particular, no me gusta la idea de agregar gtest como fuente. :)
Aquí hay un ejemplo completo de trabajo que acabo de probar. Se descarga directamente desde la web, ya sea un tarball fijo o el último directorio de subversión.
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)
El más simple CMakeLists.txt que destilé de las respuestas en este hilo y un poco de prueba y error es:
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 ya debe estar instalado en su sistema.
La solución implicó poner el directorio de fuentes de Gtest como un subdirectorio de su proyecto. He incluido el archivo CMakeLists.txt a continuación si es útil para cualquier persona.
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 )
Las suyas y las soluciones de VladLosevs son probablemente mejores que las mías. Si quiere una solución de fuerza bruta, intente esto:
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)
Lo más probable es que la diferencia en las opciones del compilador entre el archivo binario de prueba y la biblioteca de Google Test sea la culpa de dichos errores. Es por eso que se recomienda traer Google Test en el formulario de origen y compilarlo junto con sus pruebas. Es muy fácil de hacer en CMake. Simplemente invoca ADD_SUBDIRECTORY
con la ruta a la raíz de gtest y luego puede usar los objetivos de la biblioteca pública ( gtest
y gtest_main
) definidos allí. Hay más información de fondo en este hilo CMake en el grupo googletestframework.
[edit] La opción BUILD_SHARED_LIBS
solo es efectiva en Windows por ahora. Especifica el tipo de bibliotecas que quiere que CMake construya. Si lo configura en ON
, CMake los compilará como DLL a diferencia de libs estáticos. En ese caso, debe compilar sus pruebas con -DGTEST_LINKED_AS_SHARED_LIBRARY = 1 y copiar los archivos DLL producidos por el CMake en el directorio con su prueba binaria (CMake los coloca en un directorio de salida por separado de manera predeterminada). A menos que gtest en lib estática no funcione para usted, es más fácil no configurar esa opción.
Puedes obtener lo mejor de ambos mundos. Es posible utilizar ExternalProject
para descargar la fuente gtest y luego usar add_subdirectory()
para agregarla a su compilación. Esto tiene las siguientes ventajas:
- gtest se crea como parte de tu compilación principal, por lo que usa los mismos indicadores de compilación, etc., y por lo tanto evita problemas como los que se describen en la pregunta.
- No es necesario agregar las fuentes de Gtest a su propio árbol fuente.
Si se usa de forma normal, ExternalProject no realizará la descarga ni el desempaquetado en el momento de la configuración (es decir, cuando se ejecuta CMake), pero puede lograrlo con solo un poco de trabajo. He escrito una publicación de blog sobre cómo hacer esto que también incluye una implementación generalizada que funciona para cualquier proyecto externo que utilice CMake como su sistema de compilación, no solo Gtest. Usted puede encontrarlos aquí:
Actualización: este enfoque ahora también forma parte de la documentación de googletest .