Интерфейсы против шаблонов для инъекций зависимостей в С++
Чтобы иметь возможность unit test моего кода на С++, я обычно передаю конструктор класса под одним или несколькими объектами, которые могут быть либо "производственным кодом", либо фальшивыми/макетными объектами (позвольте назвать эти объекты инъекции). Я сделал это либо
- Создание интерфейса, который наследует класс "производственный код" и класс fake/mock.
- Выполнение класса под классом шаблона, который принимает типы объектов инъекции в качестве параметров шаблона, и экземпляры объектов инъекции в качестве параметров для конструктора.
Некоторые случайные мысли:
- До тех пор, пока у нас нет понятий (С++ 0x), только документация и именование параметров подскажут, что обеспечить тестируемый класс (при использовании шаблонов).
- Не всегда возможно создавать интерфейсы для устаревшего кода
- Интерфейс в основном создан только для того, чтобы иметь возможность делать инъекции зависимостей
- Точно так же: шаблонный тест класса выполняется только для включения инъекции зависимостей
Каковы ваши мысли? Существуют ли другие решения этой проблемы?
Ответы
Ответ 1
Я думаю, что опция интерфейса лучше, но не нужно создавать общий базовый класс только для теста. Вы можете наследовать свой макет класса из производственного класса и переопределить необходимые методы. Вы должны будете сделать методы виртуальными, но, что инструменты, такие как mockpp работают, и они также позволяют автоматизировать этот процесс немного.
Ответ 2
С С++ существует еще один вариант - вы даете своим макетным классам те же имена, что и реальные классы, и при связывании своих модульных тестов просто связывайте их с файлами mock object/library вместо реальных.
Ответ 3
Шаблоны будут иметь немного меньшие штрафы за производительность во время выполнения (меньше указаний, меньше вызовов, больше встроенных оптимизаций), но заставит вас страдать очень высоким штрафом за время компиляции...
Я думаю, что для этой цели интерфейсы лучше (пока у нас не будет понятий в С++ 0x TR1)... если только вы не можете замедлить некоторые "узкие места". Интерфейсы более динамичны и могут переключаться во время выполнения.
Помните, что вы можете построить свой класс с объектами инъекции по умолчанию (реальными), но у вас могут быть фабрики, которые вводят макеты в ваши тесты... вам даже не нужно подклассы.
Ответ 4
Не знаю, помогает ли это, но вы можете иметь конструкторы шаблонов:
struct Class_Under_Test
{
template <typename Injected>
Class_Under_Test()
{
...
// and even specialize them
template <>
Class_Under_Test <A_Specific_Injection_Class>
{
...
Будет включен только тот, который на самом деле используется.