我有一个使用类Bar的类Foo。Bar仅在Foo中使用,而且Foo管理Bar,因此我使用unique_ptr(而不是引用,因为我不需要在Foo外部使用Bar):
我有一个名为Foo的类,该类使用Bar类。Bar类仅被Foo类使用,而且Foo类管理Bar类,因此我使用了unique_ptr(而不是引用),因为我不需要在Foo类外部使用Bar类:
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的可能选项:
- 使用shared_ptr: 在这种情况下过于繁琐(Bar对象不在Foo和其他任何对象之间共享)
- 通过IBar引用: 不是一个选择(Bar没有存储在Foo之外,所以创建的Bar对象将被销毁,使Foo保留悬挂引用)
- 通过unique_ptr: 无法以此方式进行测试
- 传值:不可能(同unique_ptr一样,将发生复制)。
我得到的唯一解决方案是在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;
};
难道没有更简洁的解决方案吗?我必须使用静态依赖注入(模板)吗?