Как тестировать приватные функции библиотеки (TDD) с помощью CMake - PullRequest
0 голосов
/ 12 февраля 2019

Я хочу настроить свой проект с помощью CMake, чтобы он мог быть разработан с использованием TDD, что означает , включая и тестируя внутренние заголовки .Но правильная настройка библиотеки с помощью CMake скрывает эти детали реализации (и правильно для внешнего использования) от моих модульных тестов.

При такой структуре файлов и папок:

Foo
|-- include
|   `-- Foo
|       `-- Foo.h
|-- CmakeLists.txt
|-- src
|   |-- Bar
|   |   |-- Bar.h
|   |   `-- Bar.cpp
|   |-- Baz
|   |   |-- Baz.h
|   |   `-- Baz.cpp
|   |-- Foo.cpp
|   `-- CMakeLists.txt
`-- test
    |-- Bar
    |   `-- BarTest.cpp
    |-- Baz
    |   `-- BazTest.cpp
    |-- FooTest.cpp
    `-- CMakeLists.txt

Foo/CMakeLists.txt

project(Foo)
include(CTest)
add_subdirectory(src)
if(BUILD_TESTING)
    add_subdirectory(test)
endif()

Foo / src / CMakeLists.txt

add_library(Foo)
target_include_directories(Foo
    PUBLIC
        $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include>
    PRIVATE
        ${CMAKE_CURRENT_LIST_DIR}
)

target_sources(Foo
    PRIVATE
        Foo.cpp
        Bar/Bar.cpp
        Baz/Baz.cpp
)

Foo / test / CMakeLists.txt

find_package(Catch2 REQUIRED)
include(Catch)

add_executable(FooTest
    FooTest.cpp
    Bar/BarTest.cpp # This file can't #include "Bar/Bar.h"
    Baz/BazTest.cpp # This file can't #include "Baz/Baz.h"
)

target_link_libraries(FooTest
    PRIVATE
        Foo
        Catch2::Catch2
)

Теперь проблема заключается в том, чтоFooTest связывается с Foo так, как это делают другие проекты, когда им нужна библиотека Foo в качестве зависимости.Это создает проблему, из-за которой я не могу запустить модульные тесты в Bar/BarTest.cpp и Baz/BazTest.cpp, которые включают файлы #include "Bar/Bar.h" и #include "Baz/Baz.h.В идеале, на мой взгляд, решение могло бы получить внутреннюю цель shortcut для Foo, которая включает в себя все как PUBLIC, на котором я могу запускать тесты.Но при установке внутренние заголовки являются частными, и только файлы в include/Foo/ являются общедоступными.

Решения, которые я видел, - это либо создать много подцелей и включить в них только то, что вам нужно для каждого теста.Но это кажется громоздким и не очень хорошо подходит для менеджеров пакетов, таких как Конан, в очень модульной конфигурации.

Другое решение - создать дублирующую цель Foo, где все открыто, но для этого нужно, чтобы я писал все дважды.Звучит как грязный путь для меня.

Последнее решение, о котором я подумал, - это создать внутреннюю цель FooInternal с каждым заголовком и источником, установленным в public, с которым затем FooTest может связать.Затем создайте библиотеку обёрток как Foo, которая связывает FooInternal как частную, но устанавливает папку include/Foo в качестве общедоступных заголовков.Но для этого требуется, чтобы Foo был целью интерфейса, который затем не будет экспортировать libFoo, чтобы я мог создать собственную логику для переименования или каким-то образом настроить CMake для использования libFooInternal в качестве правильного файла lib.Опять же, это звучит грязно, и я не уверен, как это будет работать на практике.

Существуют ли очевидные решения, о которых я не замечаю, или у кого-нибудь есть хорошее решение этой проблемы?

1 Ответ

0 голосов
/ 13 февраля 2019

edit3: Решение из edit2 на самом деле не будет хорошо работать с деревьями сборки, которые содержат несколько библиотек, потому что оно дает целям доступ к внутренним заголовкам связанных целей.Решение, предложенное Брэдом Кингом для gitlab Kitakes CMake, которое в конечном итоге использовалось:

add_library(foo foo.c)
target_include_directories(foo PUBLIC "$<BUILD_INTERFACE:$<$<BOOL:$<TARGET_PROPERTY:FOO_PRIVATE>>:/path/to/foo/private/include>>")
set_property(TARGET foo PROPERTY FOO_PRIVATE 1)

add_executable(test_foo test_foo.c)
target_link_libraries(test_foo foo)
set_property(TARGET test_foo PROPERTY FOO_PRIVATE 1)

source: https://gitlab.kitware.com/cmake/cmake/issues/19048


edit2: окончательное решение, которое оказалось до смешного простым, было простоустановить для путей включения значение

target_include_directories(Foo
    PUBLIC
        $<INSTALL_INTERFACE:include>
        $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
        $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
)

edit1: После просмотра видео, связанного с steveire, видно, что в последнее время я слишком мало занимался программированием и тестированием и слишком много ориентировал на devops.Мне нужно иметь возможность тестировать внутренние заголовки.Вернемся к исходной проблеме о том, как правильно ее протестировать с помощью CMake с заданной настройкой.Я обновлю этот ответ, когда найду убедительное решение.


Оригинал: После комментариев и обсуждения Superlokkus о слабости cpplang, кажется, лучше никогда не проверять внутренние заголовки.Если число абстракций между тестами, использующими открытые заголовки, и внутренним файлом .cpp слишком велико, разбейте его на отдельную библиотеку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...