У меня есть следующая структура проекта:
- include
- func.h
- src
- main.cpp
- func.cpp
- tests
- CMakeLists.txt
- func1_test.cpp
- func2_test.cpp
- CMakeLists.txt
Вот корень CMakeLists.txt
:
cmake_minimum_required (VERSION 3.12)
option(BUILD_TESTS "BuildTests" ON)
set(PROJECT_VERSION "0.0.3" CACHE INTERNAL "Version")
project ("test_project" VERSION ${PROJECT_VERSION})
add_executable (test_project "src/main.cpp" "src/func.cpp" "include/func.h")
include_directories("include")
set_property(TARGET test_project PROPERTY CXX_STANDARD 20)
# Enable Hot Reload for MSVC compilers if supported.
if (POLICY CMP0141)
cmake_policy(SET CMP0141 NEW)
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
endif ()
set_target_properties(test_project
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)
# Tests.
if (BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif ()
А вот тесты CMakeLists.txt
:
include(FetchContent)
if (POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif ()
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
include(GoogleTest)
set(TestsToRun
func1_test.cpp
func2_test.cpp
)
create_test_sourcelist (Tests CppTests.cpp ${TestsToRun})
add_executable (CppTests ${Tests})
target_include_directories(CppTests PRIVATE "include")
set_property(TARGET CppTests PROPERTY CXX_STANDARD 20)
target_link_libraries(CppTests GTest::gtest_main)
set_target_properties(CppTests
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)
foreach (test ${TestsToRun})
get_filename_component (TName ${test} NAME_WE)
add_test (NAME ${TName} COMMAND CppTests ${TName})
#gtest_discover_tests(${test})
endforeach ()
func.h
:
#pragma once
int func1();
int func2();
func.cpp
:
#include "func.h"
int func1()
{
return 33;
}
int func2()
{
return 77;
}
Я пытаюсь использовать create_test_sourcelist
из документации CMake. Но построение дает мне следующую ошибку:
[main] Building folder: /home/user/Code/Test/build/linux-debug
[build] Starting build
[proc] Executing command: /usr/bin/cmake --build /home/user/Code/Test/build/linux-debug --parallel 22 --
[build] [ 20%] Built target test_project
[build] [ 33%] Built target gtest
[build] [ 46%] Built target gtest_main
[build] [ 60%] Built target gmock
[build] [ 73%] Built target gmock_main
[build] [ 80%] Linking CXX executable ../bin/CppTests
[build] /usr/bin/ld: CMakeFiles/CppTests.dir/CppTests.cpp.o:(.data.rel.ro+0x8): undefined reference to `func1_test(int, char**)'
[build] /usr/bin/ld: CMakeFiles/CppTests.dir/CppTests.cpp.o:(.data.rel.ro+0x18): undefined reference to `func2_test(int, char**)'
[build] /usr/bin/ld: CMakeFiles/CppTests.dir/func1_test.cpp.o: in function `Func1Test_Func1Test_Test::TestBody()':
[build] /home/user/Code/Test/tests/func1_test.cpp:9:(.text+0x28): undefined reference to `func1()'
[build] /usr/bin/ld: CMakeFiles/CppTests.dir/func2_test.cpp.o: in function `Func21Test_Func2Test_Test::TestBody()':
[build] /home/user/Code/Test/tests/func2_test.cpp:9:(.text+0x28): undefined reference to `func2()'
[build] collect2: error: ld returned 1 exit status
[build] gmake[2]: *** [tests/CMakeFiles/CppTests.dir/build.make:131: bin/CppTests] Error 1
[build] gmake[1]: *** [CMakeFiles/Makefile2:180: tests/CMakeFiles/CppTests.dir/all] Error 2
[build] gmake: *** [Makefile:146: all] Error 2
[proc] The command: /usr/bin/cmake --build /home/user/Code/Test/build/linux-debug --parallel 22 -- exited with code: 2
[driver] Build completed: 00:00:00.352
[build] Build finished with exit code 2
Обратите внимание: я прокомментировал вызов gtest_discover_tests
, потому что не понимаю, стоит ли мне его использовать и какую переменную для этого использовать.
Вот func1_test.cpp
(func2_test.cpp
выглядит похоже):
#include <sstream>
#include <limits>
#include <gtest/gtest.h>
#include "../include/func.h"
TEST(Func1Test, Func1Test)
{
ASSERT_EQ(func1(), 33);
}
Во-первых, чтобы протестировать код в func.cpp
, вам следует создать библиотеку, а затем связать ее как с основным исполняемым файлом, так и со своими тестами. Затем я вижу, что вы создали один исполняемый файл теста CppTests
, если вы хотите, чтобы он был исполняемым с помощью CTest, то есть набрав make test
, этого достаточно: add_test(MyTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CppTests)
Основная проблема заключается в том, что исходные коды, которые необходимо протестировать, собираются как часть целевого исполняемого файла: test_project
! Вам нужна библиотека, которую вы свяжете с исполняемым файлом и тестами.
Переставьте источники следующим образом:
- funlib
- include
- funlib
- func.h
- src
- func.cpp
- CMakeLists.txt
- demo_app
- main.cpp
- CMakeLists.txt
- tests
- CMakeLists.txt
- func1_test.cpp
- func2_test.cpp
- CMakeLists.txt
Где:
funlib
- каталог библиотеки
include
предназначен для публичных заголовков библиотеки (публичный интерфейс библиотеки)src
— для исходников funlib
s и частных заголовков.demo_app
ваш конечный продукт, который должен делать как можно меньше и просто вызывать некоторые библиотечные функции.tests
— актуальные тесты для тестовой библиотекиCMakelists.txt
cmake_minimum_required (VERSION 3.12)
option(BUILD_TESTS "BuildTests" ON)
set(PROJECT_VERSION "0.0.3" CACHE INTERNAL "Version")
project (test_project VERSION ${PROJECT_VERSION})
add_subdirectory(funlib)
add_subdirectory(demo_app)
if (BUILD_TESTS)
add_subdirectory(tests)
endif ()
funlib/CMakeLists.txt
add_library(funlib # STATIC?
src/func.cpp
include/funlib/func.h
)
target_include_directories(funlib
PUBLIC include
PRIVATE src include/funlib)
Обратите внимание, что в этой форме вы будете использовать #include <funlib/func.h>
в других целях для импорта функции.
demo_app/CMakeLists.txt
add_executable(demo_app main.cpp)
target_link_libraries(demo_app PUBLIC funlib)
tests/CMakeLists.txt
# importing gtest ....
# I do not like how you do it, but this is off topic of your question
add_executable(CppTests
func1_test.cpp
func2_test.cpp
)
target_link_libraries(CppTests PUBLIC GTest::gtest_main funlib)
gtest_discover_tests(CppTests)
Обратите внимание, что путь включения уже указан в funlib
, вам не следует делать это в CppTests
.
«Я пытаюсь использовать create_test_sourcelist» — он вам не нужен. Просто используйте
add_executable("CppTests" "CppTests.cpp" "func1_test.cpp" " func2_test.cpp" "func.cpp")