c++ - CMake: estructura del proyecto con pruebas unitarias
unit-testing boost (2)
Me gusta el ejemplo de @Fraser pero usaría el comando add_test en la prueba / CMakeLists.txt y usar enable_testing antes de add_subdirectory (test).
De esta forma, puede ejecutar sus pruebas desde el directorio de compilación de nivel superior mientras especifica sus pruebas en la prueba / CMakeLists.txt.
El resultado sería así (reutilicé el ejemplo 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)
prueba / 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)
Estoy tratando de estructurar mi proyecto para incluir las fuentes de producción (en la subcarpeta src
) y las pruebas (en la subcarpeta de test
). Estoy usando CMake para construir esto. Como un ejemplo mínimo, tengo los siguientes archivos:
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 - usa sqr, realmente no importa
prueba / 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));
}
Unas cuantas preguntas:
- ¿Tiene esta estructura sentido? ¿Cuáles son las mejores prácticas al estructurar este código? (Vengo de C # y Java, y allí es más fácil en cierto sentido)
- No me gusta el hecho de que tengo que listar todos los archivos de la carpeta
src
en el archivotest/CMakeLists.txt
. Si se tratara de un proyecto de biblioteca, simplemente vincularía la biblioteca. ¿Hay alguna manera de evitar enumerar todos los archivos cpp del otro proyecto? - ¿Qué están
enable_testing()
las líneasenable_testing()
yadd_test(MyTest test)
? No he visto ningún efecto. ¿Cómo puedo ejecutar las pruebas desde CMake (o CTest)? - Hasta ahora solo corrí
cmake .
en la carpeta raíz, pero esto creó un lío con archivos temporales en todas partes. ¿Cómo puedo obtener los resultados de la compilación en una estructura razonable?
Para las preguntas 1 y 2, recomendaría crear una biblioteca a partir de los archivos que no son de prueba, excluyendo main.cpp (en este caso, solo src / sqr.cpp y src / sqr.h), y luego puede evitar el listado (y más importante aún) volver a compilar) todas las fuentes dos veces.
Para la pregunta 3, estos comandos agregan una prueba llamada "MyTest" que invoca su "prueba" ejecutable sin ningún argumento. Sin embargo, dado que ha agregado estos comandos para probar / CMakeLists.txt y no su CMakeLists.txt de nivel superior, solo puede invocar la prueba desde el subdirectorio "prueba" de su árbol de compilación (pruebe cd test && ctest -N
) Si desea que la prueba sea ejecutable desde su directorio de compilación de nivel superior, deberá llamar a add_test
desde el CMakeLists.txt de nivel superior. Esto también significa que tienes que usar la forma más detallada de add_test
ya que tu prueba exe no está definida en el mismo CMakeLists.txt
En su caso, dado que ejecuta cmake en la carpeta raíz, su árbol de compilación y su árbol fuente son uno y el mismo. Esto se conoce como una creación en fuente y no es ideal, lo que lleva a la pregunta 4.
El método preferido para generar el árbol de compilación es hacer una compilación fuera de la fuente, es decir, crear un directorio en algún lugar fuera de su árbol fuente y ejecutar cmake desde allí. Incluso crear un directorio "build" en la raíz de su proyecto y ejecutar cmake ..
proporcionaría una estructura limpia que no interferirá con su árbol fuente.
Un último punto es evitar llamar a los ejecutables "prueba" (distingue entre mayúsculas y minúsculas). Por las razones, mira esta respuesta .
Para lograr estos cambios, haría lo siguiente:
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)
prueba / 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}
)