Внедрение зависимостей с 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;
};

Разве нет более чистого решения? Нужно ли использовать статическое внедрение зависимостей (шаблоны)?

Ответы на вопрос(1)

Ваш ответ на вопрос