Как использовать несколько GTests в CMake

У меня есть следующая структура проекта:

- 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);
}

«Я пытаюсь использовать create_test_sourcelist» — он вам не нужен. Просто используйте add_executable("CppTests" "CppTests.cpp" "func1_test.cpp" " func2_test.cpp" "func.cpp")

user7860670 29.07.2024 10:47

Во-первых, чтобы протестировать код в func.cpp, вам следует создать библиотеку, а затем связать ее как с основным исполняемым файлом, так и со своими тестами. Затем я вижу, что вы создали один исполняемый файл теста CppTests, если вы хотите, чтобы он был исполняемым с помощью CTest, то есть набрав make test, этого достаточно: add_test(MyTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CppTests)

pptaszni 29.07.2024 10:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Основная проблема заключается в том, что исходные коды, которые необходимо протестировать, собираются как часть целевого исполняемого файла: 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 — для исходников funlibs и частных заголовков.
  • 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.

Другие вопросы по теме