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