Интерфейсы и шаблоны для внедрения зависимостей в C ++ - PullRequest
23 голосов
/ 15 июля 2009

Чтобы иметь возможность модульного тестирования моего кода C ++, я обычно передаю конструктору тестируемого класса один или несколько объектов, которые могут быть либо «рабочим кодом», либо поддельными / фиктивными объектами (давайте назовем эти объекты внедрения). Я сделал это либо

  1. Создание интерфейса, который наследуется как классом «production code», так и классом fake / mock.
  2. Создание тестируемого класса шаблонным классом, который принимает типы объектов внедрения в качестве параметров шаблона, а экземпляры объектов внедрения - в качестве параметров для конструктора.

Несколько случайных мыслей:

  • Пока у нас нет концепций (C ++ 0x), только документация и именование параметров будут подсказывать, что предоставить тестируемый класс (при использовании шаблонов).
  • Не всегда возможно создать интерфейсы для устаревшего кода
  • Интерфейс в основном создается только для внедрения зависимостей
  • Точно так же: шаблонирование тестируемого класса выполняется только для включения внедрения зависимости

Что ты думаешь? Есть ли другие решения этой проблемы?

Ответы [ 4 ]

8 голосов
/ 15 июля 2009

В C ++ есть еще один вариант - вы даете своим фиктивным классам точно такие же имена, что и реальным классам, а при связывании своих модульных тестов просто связываете их с файлами фиктивных объектов / библиотек вместо реальных.

4 голосов
/ 15 июля 2009

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

3 голосов
/ 15 июля 2009

Шаблоны будут иметь немного меньшие потери производительности для времени выполнения (меньше косвенных обращений, меньше вызовов, больше встроенных оптимизаций), но заставят вас понести очень высокий штраф за время компиляции ...

Я думаю, что для этой цели интерфейсы лучше (пока у нас нет концепций в C ++ 0x TR1) ... если только вы не можете замедлить некоторый "код узкого места". Интерфейсы более динамичны и переключаемы во время выполнения.

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

2 голосов
/ 15 июля 2009

Не знаю, поможет ли это, но у вас могут быть конструкторы шаблонов:

struct Class_Under_Test
{
    template <typename Injected>
    Class_Under_Test()
    {
         ...

    // and even specialize them
    template <>
    Class_Under_Test <A_Specific_Injection_Class>
    {
        ...

Будет включен только тот, который действительно используется.

...