我有一个使用Foo类的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的可能选项:
shared_ptr的
通过引用IBar来实现
我得到的唯一解决方案是在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;
};
没有更清洁的解决方案吗?我必须使用静态依赖注入(inject)(模板)吗?
最佳答案
我实际上不建议在生产环境中使用某些东西,但是shared_ptr
的别名构造函数可能代表您的情况的肮脏且可行的解决方案。
一个最小的可行示例(不使用gtest,对不起,我来自移动应用程序,无法直接对其进行测试):
#include<memory>
#include<iostream>
#include<utility>
struct IBar {
virtual ~IBar() = default;
virtual void DoSth() = 0;
};
struct Bar : public IBar {
void DoSth() override { std::cout <<"Bar is doing sth" << std::endl;};
};
struct Foo {
Foo(std::unique_ptr<IBar> bar) : bar(std::move(bar)) {}
void DoIt() {
bar->DoSth();
}
private:
std::unique_ptr<IBar> bar;
};
int main() {
std::unique_ptr<Bar> bar = std::make_unique<Bar>();
std::shared_ptr<Bar> shared{std::shared_ptr<Bar>{}, bar.get()};
Foo foo{std::move(bar)};
shared->DoSth();
foo.DoIt();
}
我想您的测试会变成这样:
struct BarMock: public IBar {
MOCK_METHOD0(DoSth, void());
};
struct FooTest : public testing::Test {
FooTest() {
std::unique_ptr<BarMock> bar = std::make_unique<BarMock>();
barMock = std::shared_ptr<BarMock>{std::shared_ptr<BarMock>{}, bar.get()};
out = std::make_unique<Foo>{std::move(bar)};
}
std::shared_ptr<BarMock> barMock;
std::unique_ptr<Foo> out;
};
TEST_F(FooTest, shouldDoItWhenDoSth) {
EXPECT_CALL(*barMock, DoSth());
out->DoIt();
}
aliasing constructor是做什么的?
template< class Y >
shared_ptr( const shared_ptr<Y>& r, element_type *ptr );
关于c++ - 依赖注入(inject)与unique_ptr一起模拟,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40508033/