Внедрение зависимостей с unique_ptr для имитации
У меня есть класс Foo, который использует класс Bar. Bar используется только в Foo, а Foo управляет Bar, поэтому я использую unique_ptr (не ссылку, потому что мне не нужен Bar вне Foo):
using namespace std;
struct IBar {
virtual ~IBar() = default;
virtual void DoSth() = 0;
};
struct Bar : public IBar {
void DoSth() override { cout <<"Bar is doing sth" << endl;};
};
struct Foo {
Foo(unique_ptr<IBar> bar) : bar_(std::move(bar)) {}
void DoIt() {
bar_->DoSth();
}
private:
unique_ptr<IBar> bar_;
};
Пока все хорошо, это работает отлично. Однако у меня возникает проблема, когда я хочу выполнить модульное тестирование кода:
namespace {
struct BarMock : public IBar {
MOCK_METHOD0(DoSth, void());
};
}
struct FooTest : public Test {
FooTest() : barMock{ make_unique<BarMock>() }, out(std::move(barMock)) {}
unique_ptr<BarMock> barMock;
Foo out;
};
TEST_F(FooTest, shouldDoItWhenDoSth) {
EXPECT_CALL(*barMock, DoSth());
out.DoIt();
}
Тест не пройден, потому что фиктивный объект был передан для Foo, и установка ожидания для такой фиктивной попытки не удалась.
Возможные варианты DI:
by shared_ptr: слишком много в этом случае (объект Bar не разделяется между Foo и другими)по ссылке на IBar: не вариант (Bar не сохраняется вне Foo, поэтому созданный объект Bar будет разрушен, оставляя Foo с висячей ссылкой)by unique_ptr: не тестируется в представленном видепутем передачи по значению: невозможно (копирование произойдет - та же проблема, что и с unique_ptr).Единственное решение, которое я получил, - это сохранить необработанный указатель на BarMock до того, как Foo станет единственным владельцем BarMock, т.е.
struct FooTest : public Test {
FooTest() : barMock{new BarMock} {
auto ptr = unique_ptr<BarMock>(barMock);
out.reset(new Foo(std::move(ptr)));
}
BarMock* barMock;
unique_ptr<Foo> out;
};
Разве нет более чистого решения? Нужно ли использовать статическое внедрение зависимостей (шаблоны)?