Модульное тестирование неэкспортированных классов в DLL
Мы разрабатываем приложение на C++ с использованием Visual Studio 2008, а модульное тестирование - с помощью Boost.Test. На данный момент у нас есть отдельное решение, которое содержит наши модульные тесты.
Многие из наших проектов в основном решении производят DLL. Мы ограничены в тестовом покрытии, потому что мы не можем тестировать неэкспортированные классы.
У меня есть две идеи о том, как их можно проверить:
- Экспортировать все
- Поместите тесты в DLL (тот же проект и решение) и используйте внешний бегун Boost.Test
Я не совсем уверен, какие будут недостатки. Номер 1 выше нарушает инкапсуляцию на уровне модуля, а номер 2 может привести к гораздо большей DLL, если только в определенных конфигурациях возможно включить тестовый код.
Итак, есть ли серьезные недостатки вышеупомянутых методов, или вы можете подумать о других решениях?
4 ответа
Развивая ответ Тома Куарендона на этот вопрос, я использовал небольшой вариант ответа Саймона Стила:
- Создайте тестовый проект (используя любую тестовую среду, которая вам нравится, я использую CppUnit).
- В вашем test_case.cpp,
#include <header/in/source/project.h>
, - В свойствах тестового проекта:
- В Linker->General добавьте исходный проект
$(IntDir)
в каталоги дополнительных библиотек. - В Linker->Input добавьте
.obj
файлы к дополнительным зависимостям.
- В Linker->General добавьте исходный проект
- Добавьте зависимость из тестового проекта в исходный проект в Project->Project Dependencies.
Опять же, единственные накладные расходы по обслуживанию являются стандартными для юнит-тестов - чтобы создать зависимость от юнитов, которые вы хотите протестировать.
Решение, которое я использую для этого, состоит в том, чтобы встроить тот же неэкспортированный код в мою тестовую DLL. Это увеличивает время сборки и означает добавление всего в оба проекта, но экономит на экспорте всего или помещает тесты в основной код продукта.
Другой возможностью было бы скомпилировать неэкспортированный код в библиотеку, которая используется как библиотекой DLL с экспортом, так и проектом модульного теста.
Также искал решение, возможно, будет легче поддерживать следующее.
Добавьте новую конфигурацию сборки, например "Отладка модульного тестирования", в проект DLL и измените тип конфигурации на "Static Library .lib" ("Общие"->"Тип конфигурации").
Затем просто добавьте зависимость ваших модульных тестов от этого проекта, теперь все должно связываться воедино при использовании новой конфигурации сборки "Отладка модульного тестирования". Если вы используете сборки выпуска для модульных тестов, вам нужно добавить еще одну конфигурацию с оптимизацией выпуска.
Итак, преимущества этого решения:
- низкая стоимость обслуживания
- один проект DLL/ статическая библиотека
- не нужно вручную ссылаться на файлы.obj
Недостатки:
- Дополнительные профили конфигурации потребуют некоторых изменений в вашей среде сборки (CI)
- Больше времени компиляции
Обновление: мы фактически использовали другой подход.
Мы добавили новые конфигурации "Test debug"/"Test release" для каждого имеющегося у нас проекта.
Для проектов.exe/.dll мы отключаем исходный файл main.cpp от компиляции и заменяем его на тот, который создает экземпляр тестовой среды (например, gtest) и запускает все тесты, тесты находятся в отдельных файлах.cpp, которые также исключаются из Компиляция в обычных конфигурациях (Release/Debug) и включена только в тестовых конфигурациях.
Для проектов.lib у нас также есть новые конфигурации "Test debug"/"Test release", и мы преобразуем статическую библиотеку в файл.exe и предоставляем main.cpp, который создает экземпляр инфраструктуры тестирования, а также сам выполняет тесты и тесты. Связанные с тестом файлы исключаются из компиляции в конфигурациях выпуска / отладки.
Попробуйте создать определение, такое как следующее, где все файлы будут включать:
#define EXPORTTESTING __declspec(dllexport)
И используйте его вместо dllexport, вот так:
class EXPORTTESTING Foo
{
...
};
После этого вы сможете отключить флаг для сборки DLL-версии выпуска, но оставьте его включенным для DLL, тестируемой модулем.