【发布时间】:2017-03-23 07:49:36
【问题描述】:
我有一个使用类 Bar 的类 Foo。 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的可能选项:
- by shared_ptr:在这种情况下太多了(Bar 对象不在 Foo 之间共享任何其他)
- 通过引用 IBar:不是一个选项(Bar 不存储在 Foo 之外,因此创建的 Bar 对象将被破坏,留下 Foo 悬空引用)
- 由 unique_ptr 提供:无法以呈现的方式进行测试
- 通过值传递:不可能(复制将发生 - 与 unique_ptr 相同的问题)。
我得到的唯一解决方案是在 Foo 成为 BarMock 的唯一所有者之前存储指向 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;
};
没有更清洁的解决方案吗?我必须使用静态依赖注入(模板)吗?
【问题讨论】:
-
您可能有兴趣阅读this answer。
-
@πάντα ῥεῖ:谢谢你的链接。我已经看过它,它适用于将 unique_ptr 作为参数的方法 - 但我不确定是否可以将这种方法应用于构造函数。
标签: c++ unit-testing dependency-injection gmock