LINUX.ORG.RU

Помогите в CMake сделать отдельный от основного проект для модульного тестирования основного на C++.

 ,


1

2

У меня есть проект в виде библиотеки на плюсах.
В проекте есть класс который надо тестировать.

Есть нужда сделать отдельный тестирующий класс, расположить его в отдельном проекте, и вписать его как friend в тестируемом классе. Дилемма в том что при обычной сборке библиотеки (даже Debug) указанной строчки friend быть не должно, но для сборки теста строчка нужна.

Хочется что бы для сборки простой библиотеки нужно было просто набрать CMake и make без всяких лишних дефайнов. Для сборки теста набрать что-то вроде CMake && make test.

Допустим есть

product/CMakeFile.txt
product/lib/CMakeFile.txt
product/test/CMakFile.txt
Как в данной ситуации это лучше сделать?

★★★

Проект или цель сборки? Если проект, то чем он, в твоём понимании, отличается от цели сборки?

XMs ★★★★★
()

Лучше всего - никак. То есть вообще не делать то, что ты делаешь.

Хуже - приседаниями с препроцессором.

LamerOk ★★★★★
()
Ответ на: комментарий от cvv

Т.е. как? Допустим у меня есть цель add_library(product) и цель add_executable(test). Вторая из них должна повторять весь список исходных текстов, зависимостей и определений что и в первой? Если так, то не могу принять такой вариант, так как для первой цели у меня слишком много всего, и дублировать это я не могу.

normann ★★★
() автор топика
Ответ на: комментарий от XMs

Проект - отдельный CMakeFile.txt с командой project(). В моём случае каждый из названных проектов содержит по одной цели.

normann ★★★
() автор топика
Ответ на: комментарий от RazrFalcon

Понятно что без #ifdef не обойтись, но как грамотно составить проекты на CMake, вот вопрос.

normann ★★★
() автор топика

А зачем тебе friend в определении класса при тестировании?
В CMake есть еще и CTest, что мешает задействовать его?

ia666
()

А в чём конкретная проблема? Ну, например, добавь цель (add_executable) для теста, включи в неё исходники самого теста и тестируемого класса, friend убери под #ifdef и для цели добавь definitions выставляющий этот define. В итоге получишь для теста свой класс с включенным friend.

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

slovazap ★★★★★
()
Ответ на: комментарий от ia666

А зачем тебе friend в определении класса при тестировании?

Странный вопрос, потому что класс делает много всего, т.е. не декомпозирован как следует.

Begemoth ★★★★★
()

Есть нужда сделать отдельный тестирующий класс, расположить его в отдельном проекте, и вписать его как friend в тестируемом классе

Тут уже попахивает. Т.е. тестируемый класс должен знать о тестирующем классе? И зачем тестировать приватное поведение?

theNamelessOne ★★★★★
()

и вписать его как friend в тестируемом классе

говнокод детектед. Подпорки в продакшн коде только ради юнет тестов делать моветон. Если хочется совсем по-простому, когда классовая архитектура ещё неоптимальная и в процессе становления, проще вообще не задействовать private/public/protected, а тупо всё валить в паблик или использовать структуры с дефолтным доступом к членам. Получится анти-ООП и тоже говнокод, но не на столько сильно, как с препроцессором для friend.

seiken ★★★★★
()
Последнее исправление: seiken (всего исправлений: 1)

Если использование отдельного cmake проекта связано только с вышеописанной порнографией вокруг продакшн кода, то отдельный проект таки не нужен

seiken ★★★★★
()
Ответ на: комментарий от LamerOk

Откуда информация? Кстати ты на мой вопрос не ответил, я надеюсь на конструктив.

normann ★★★
() автор топика
Ответ на: комментарий от ia666

А зачем тебе friend ...

Что бы приватные методы тестировать.

В CMake есть еще и CTest

Я не знаю CTest, а в данный момент у меня просто нет времени с ним разбираться до выполнения моей задачи.

normann ★★★
() автор топика
Ответ на: комментарий от slovazap

добавь цель (add_executable) для теста

Не могу, корпоративные правила требуют тесты отдельным проектом.

А почему класс зависит? friend, и тот который под ifdef-ом, по моему не налагает никаких ограничений на сборку продукта.

normann ★★★
() автор топика
Ответ на: комментарий от eagleivg

Но есть время навернуть костылей

Если-бы я хотел навернуть костыле, то не обратился к публике.

normann ★★★
() автор топика
Ответ на: комментарий от normann

корпоративные правила требуют тесты отдельным проектом

Проектом в системе сборки или проектом в репозитории?

XMs ★★★★★
()
Ответ на: комментарий от seiken

Ненужно, ненужно, ...

А можно пример того что нужно? В этом и есть вопрос.

normann ★★★
() автор топика
Ответ на: комментарий от XMs

Проектом в системе сборки или проектом в репозитории?

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

normann ★★★
() автор топика
Ответ на: комментарий от normann

Не могу, корпоративные правила требуют тесты отдельным проектом.

Какая разница? add_executable можно добавить в любой проект.

А почему класс зависит? friend, и тот который под ifdef-ом, по моему не налагает никаких ограничений на сборку продукта.

Потому что этот friend класс зависит от приватного интерфейса, при том что разделение областей видимости для того и придумали чтобы ограничить протокол взаимодействия между классами публичным интерфейсом, что ведёт к уменьшению связности и, как следствие, сложности. friend за исключением очень специфичных случаев это оксюморон и нет, тесты к таким случаям не относятся. Это как построить дорогущий, качественный бетонный забор вокруг дома, но только с трёх сторон.

slovazap ★★★★★
()
Ответ на: комментарий от normann

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

Тогда не парься и обойдись просто целью в отдельном каталоге, который добавляешь через add_subdirectory(). Не вижу проблем

XMs ★★★★★
()
Ответ на: комментарий от normann

Что бы приватные методы тестировать.

А нафига? Они ж приватные, смысл их тестировать?

Я не знаю CTest, а в данный момент у меня просто нет времени с ним разбираться до выполнения моей задачи.

Не думаю, что освоение займет кучу времени, если уже знаком с CMakе. Считай просто цель добавить и всё.
Так что согласен с комментарием @eagleivg

ia666
()
Ответ на: комментарий от slovazap

Я ничего не понял. friend класс зависит от приватного интерфейса тестируемого класса, так и должно быть, он его тестирует, собираясь вместе с ним (нет?). Тестируемый класс не зависит от friend класса, так как ничего у него не вызывает и при обычной сборке без теста упоменания (этой строчки с friend) о нём вообще нету.

normann ★★★
() автор топика
Ответ на: комментарий от XMs

Тогда не парься и обойдись просто целью в отдельном каталоге, который добавляешь через add_subdirectory(). Не вижу проблем

Ну допустим я так сделаю, я тоже не вижу проблем, что мне это даёт теперь?

Я не хочу копипастить всю кучу скриптов по вычислению содержимого цели библиотеки в цель теста, хочу что бы для целей тестирования цель библиотеки собралась ещё раз, но уже с friend, а её уже подсоединить к цели теста. Так можно?

normann ★★★
() автор топика
Последнее исправление: normann (всего исправлений: 1)

Да возбмиж ты почитай доки. Это задача штатная для cmake. на это тонны статей и доков и вопрос на mail.rustackoverflow

anonymous
()
Ответ на: комментарий от normann

target_link_libraries(test product)

Не тестировать приватные методы. Лучше приватщину вытащить в отлельный класс с публичным доступом и тестировать его.

invy ★★★★★
()
Последнее исправление: invy (всего исправлений: 1)
Ответ на: комментарий от eagleivg

TDD прекрасен. Нужно только перебороть лень и начать писать минимальные тесты. То что у меня написано с TDD - там я могу спать спокойно. Там где нет - там сюрпризы регулярные (потому что test coverage ниже получается).

invy ★★★★★
()
Последнее исправление: invy (всего исправлений: 1)
Ответ на: комментарий от invy

Дело не в лени и не в покрытии тестами. Просто он принуждает писать код, который более модульный и это прекрасно. Покрытие тут не более чем приятный побочный эффект.

eagleivg ★★★★★
()
Ответ на: комментарий от invy

Я то согласен, но ситуация такая, что в классе данных не так много сколько декомпозированных методов над ними, что бы их можно было растащить на разные классы, как потом делить между классами одни и те же данные (косвенная адресация? Нет, увольте). Декомпозиция методов утаскивает кучу кода в приват, что и приводит к проблеме тестирования.

normann ★★★
() автор топика
Ответ на: комментарий от XMs

Как это в части CMake сделать, подскажи пожалуйста, сообразить не могу. Я могу в отдельном проекте что для теста, заинклудить CMakeLists.txt от библиотеки и добавить target_compile_definitions() для цели библиотеки, а потом прилинковать её к цели исполняемого файла теста?

normann ★★★
() автор топика
Последнее исправление: normann (всего исправлений: 1)
Ответ на: комментарий от normann

Как я это вижу: y тебя есть библиотека, представленная набором классов. Ты хочешь какой-то класс протестировать, и для доступа ко внутренним полям хочешь класс теста сделать friend (ужасное решение, но пусть). Значит, для сборки без тестов, например, релизной, тебе это не надо. Значит, имеет место быть раз:

#include <build-type.h>

…

class Foo
  {
	...
#ifdef TEST_BUILD
	friend class FooTest;
#endif // TEST_BUILD
	...
  };

Два (какой-нибудь build-type.h.in):

#ifndef BUILD_TYPE_H
#define BUILD_TYPE_H

#cmakedefine TEST_BUILD

#endif // BUILD_TYPE_H

Три, корневой CMakeLists.txt:

option(TEST_BUILD "Define it if tests should be built" OFF)
configure_file(build-type.h.in build-type.h)

include_directories(${CMAKE_BUILD_DIR})

Нужны тесты — делаешь

cmake -DTEST_BUILD=ON <path/to/sources>

Мне кажется, это то, чего ты хочешь. Могу ошибаться

XMs ★★★★★
()
Последнее исправление: XMs (всего исправлений: 2)
Ответ на: комментарий от XMs

Совершенно верно, отлично, то что мне сейчас нужно! Большущее спасибо за потраченное время, я запомнил твоё имя ;). И всем кто не остался в стороне тоже спасибо.

normann ★★★
() автор топика

Ты хочешь тестирующий класс сделать френдом тестируемого для того, что бы иметь доступ к приватным полям, так? Это очень плохая затея, тесты получатся очень хрупкими и почти при каждом изменении тестируемого кода будут ломаться. Тестируй поведение, а не реализацию. Т.е. используй только публичный интерфейс.

Исключения из этого правила возможны, но на то они и исключения, что бы как можно реже их применять.

dvetutnev
()
Последнее исправление: dvetutnev (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.