Предположим, что у меня есть класс C++ как так:
class A
{
public:
A()
{
}
void SetNewB( const B& _b ) { m_B = _b; }
private:
B m_B;
}
Чтобы к модульному тесту что-то вроде этого, я должен был бы повредить зависимость A от B. Так как класс A содержит на фактический объект и не указатель, я должен был бы осуществить рефакторинг этот код для взятия указателя. Кроме того, я должен был бы создать родительский интерфейсный класс для B, таким образом, я могу передать в своей собственной фальшивке B, когда я тестирую SetNewB.
В этом случае не поблочное тестирование с внедрением зависимости далее усложняет существующий код? Если я делаю B указателем, я теперь представляю выделение "кучи", и некоторая часть кода теперь ответственна за чистку его (если я не использую касательно считаемых указателей). Кроме того, если B является довольно тривиальным классом только с несколькими членскими переменными и функциями, почему представляют совершенно новый интерфейс для него вместо того, чтобы просто тестировать с экземпляром B?
Я предполагаю, что Вы могли привести аргумент, что будет легче осуществить рефакторинг при помощи интерфейса. Но есть ли некоторые случаи, где два класса, возможно, должны были бы быть сильно связаны?
Я думаю, что вы слишком далеко заходите в идее модульного тестирования. В данном случае A и B являются единым целым, т.е. A не может существовать без B. Сначала протестируйте B и убедитесь, что он проходит все специфические для B модульные тесты, а затем, когда он пройдет, протестируйте A и убедитесь, что он ведет себя так, как должен.
В зависимости от того, как вы используете B, вы можете использовать std::auto_ptr вместо указателя с подсчетом ссылок. До тех пор, пока вам не нужно передавать ссылку на B чему-то другому, что будет работать и потребует минимальных изменений кода.
Если B
действительно является зависимостью, инжектированной в A
, то вам следует рассмотреть несколько других вариантов. Первый - инжектирование B
во время конструирования:
class A
{
public:
A( const B& _b ) : m_B(_b) {}
private:
const B& m_B;
};
Если вы действительно хотите изменить B
во время жизненного цикла вашего объекта A
, то спросите себя, действительно ли вы являетесь владельцем B
. Если нет, передайте указатель на него и предположите, что тот, кто передает указатель, отвечает за его жизненный цикл - однако это непростой путь, и, возможно, вам придется использовать указатели с реф-счетом.
Если вы хотите сделать копию B для себя, то вы можете определить метод clone()
для B
. Если вы хотите создать свой собственный объект, используя информацию, содержащуюся в B
, то вы можете внедрить MyBFactory
в конструктор и использовать его с этим B
.