使用 unique_ptr 进行依赖注入来模拟
我有一个使用类 Bar 的 Foo 类.Bar 只在 Foo 中使用,Foo 正在管理 Bar,因此我使用 unique_ptr(不是参考,因为我不需要 Foo 之外的 Bar):
I have a class Foo that uses class Bar. Bar is used only in Foo and Foo is managing Bar, therefore I use unique_ptr (not a reference, because I don't need Bar outside of 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_;
};
到目前为止一切顺利,这工作正常.但是,当我想对代码进行单元测试时遇到了问题:
So far so good, this works fine. However, I have a problem when I want to unit test the code:
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 传输的,并且对此类模拟设置期望失败.
The test fails because the mock object was transfered fo Foo, and setting an expectation on such mock fails.
DI 的可能选项:
- by shared_ptr:在这种情况下太多了(Bar 对象不会在 Foo 之间共享任何其他东西)
- 通过引用 IBar:不是一个选项(Bar 不存储在 Foo 之外,因此创建的 Bar 对象将被破坏,留下 Foo 的悬空引用)
- by unique_ptr:无法以所提供的方式进行测试
- 通过值传递:不可能(会发生复制 - 与 unique_ptr 相同的问题).
我得到的唯一解决方案是在 Foo 成为 BarMock 的唯一所有者之前存储指向 BarMock 的原始指针,即:
The only solution I got is to store raw pointer to BarMock before Foo become solely owner of BarMock, i.e.:
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;
};
没有更干净的解决方案吗?我是否必须使用静态依赖注入(模板)?
Isn't there a cleaner solution? Do I have to use static dependency injection (templates)?
推荐答案
毕竟,我最终在任何地方都使用了这种方法:
After all, I ended up using this approach everywhere:
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;
};
它与 gtest/gmock
一起工作得很好.
and it works fine with gtest/gmock
.
相关文章