C ++ вопрос о внедрении зависимостей и модульных тестах - PullRequest
1 голос
/ 07 апреля 2011

Предположим, у меня есть класс BigClass, которому нужна переменная-член типа SmallClass

class BigClass {
.....
private:
SmallClass obj;
};

У меня 2 проблемы:

1) Я не могу передать объект SmallClass в конструктор BigClass, так какBigClass должен обработать некоторые файлы (и получить некоторые данные), чтобы правильно создать экземпляр SmallClass.Я знаю, что правильный способ внедрения зависимостей - иметь конструктор BigClass(SmallClass& obj).Как решить эту проблему, если создание экземпляра SmallClass возможно только после того, как BigClass просуществовал некоторое время?

2) Вот как BigClass создает себя: он просматривает файлы в каталоге, читает некоторые файлы для инициализацииего состояние.Как я могу сделать это устройство тестируемым?Что такое правильный модульный тест для конструкторов, которые читают файлы из каталогов, чтобы получить состояние?

Ответы [ 6 ]

1 голос
/ 07 апреля 2011

1) Для меня вам нужно ввести фабрику для SmallClass и иметь BigClass в зависимости от нее для построения экземпляров SmallClass.

2) Мне кажется, что иметь это в конструкторе - плохая идея, возможно, поможет какой-то явный метод (но для правильного ответа требуется больше).

0 голосов
/ 07 апреля 2011

BigClass необходимо обработать некоторые файлы ... чтобы правильно создать экземпляр SmallClass

Я бы не советовал конструкторам выполнять ввод / вывод. Рассмотрите возможность изменения BigClass, чтобы ввод-вывод выполнялся вне (перед) вызова конструктора BigClass, а результаты этого ввода-вывода передаются в конструктор BigClass.

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

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

0 голосов
/ 07 апреля 2011

1) Создайте фабрику и для модульного теста измените метод, который создает объект, чтобы вместо него создать макет.

2) Вы можете создать другой класс с интерфейсом и производным, который является оболочкой для вызовов для получения списка файлов. Затем для модульного теста вы передаете фиктивный объект. Вы можете либо передать объект этого класса в конструктор BigClass, либо использовать фабрику.

для 1), это что-то вроде этого (не проверено):

struct Factory
{
  static SmallClassIface* Create()
  {
    return ReallyCreate();
  }

  typedef SmallClassIface* (funcPtr*)();

  static funcPtr creator;

  static SmallClassIface* DefaultCreator()
  {
    return new SmallClass;
  }
};
Factory::funcPtr Factory::creator = &Factory::DefaultCreator();
0 голосов
/ 07 апреля 2011

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

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

Другой вариант может заключаться в том, чтобы использовать SmallClass * в BigClass и использовать фабрику, которая создает объект SmallClass, и использовать ее для управления внедрением зависимостей.

0 голосов
/ 07 апреля 2011

1) Просто создайте функцию в BigClass, которую вы можете передать в объект SmallClass, когда захотите. Не обязательно быть в конструкторе func(SmallClass* obj)

2) Я бы провёл модульное тестирование вашего BigClass, который читает файлы, если ваша программа создаст кучу файлов и выбросит их в каталог. Затем запустите bigClass для этих файлов и протестируйте отдельные операции чтения на известных выходных данных, которые BigClas должен предоставить, а также на любой другой функциональности, которую вы хотите протестировать. Затем удалите файлы, когда закончите.

0 голосов
/ 07 апреля 2011

Turn

SmallClass obj;

в

SmallClass* obj;

Затем создайте метод

setObj(SmallClass* _obj);

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

...