Injeção de dependência com unique_ptr para simulação
Eu tenho uma classe Foo que usa a classe Bar. Bar é usado apenas no Foo e Foo está gerenciando o Bar, portanto, uso unique_ptr (não uma referência, porque não preciso do Bar fora do 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_;
};
Até aí tudo bem, isso funciona bem. No entanto, tenho um problema quando quero testar o código da unidade:
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();
}
O teste falha porque o objeto de simulação foi transferido para o Foo, e a definição de uma expectativa para essa simulação falha.
Possíveis opções de DI:
por shared_ptr: é demais nesse caso (o objeto Bar não é compartilhado entre Foo mais nada)por referência ao IBar: não é uma opção (o Bar não é armazenado fora do Foo, portanto o objeto Bar criado seria destruído, deixando o Foo com referência pendente)por unique_ptr: não é testável da maneira apresentadapassando por valor: não é possível (a cópia ocorrerá - o mesmo problema que com unique_ptr).A única solução que obtive é armazenar o ponteiro bruto para o BarMock antes que o Foo se torne o único proprietário do BarMock, ou seja:
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;
};
Não existe uma solução mais limpa? Preciso usar injeção de dependência estática (modelos)?