我想测试一个应用 Thud
,它将使用资源 Foo
。它不会拥有一个具体的对象,但会有一个指向抽象资源接口(interface)的指针(此处为 IFoo
)。在生产中,我将为它提供实际的资源实现 (FooImpl
),而对于单元测试,我想发送一个指向模拟资源的指针。我应该怎么做?我已经尝试编写最少的代码来说明问题,
class IFoo
{
public:
virtual bool Foo(bool) = 0;
};
class FooImpl : public IFoo
{
public:
bool Foo(bool b) override
{
return b;
}
};
class FooMock : public IFoo
{
public:
MOCK_METHOD1(Foo, bool(bool));
};
class ThudTest : public ::testing::Test
{
protected:
virtual void SetUp() {
//foo.reset(&mock); //line#1
foo = &mock; //line#2
}
FooMock mock;
//std::shared_ptr<IFoo> foo; //line#3
IFoo* foo; //line#4
};
class Thud
{
//std::shared_ptr<IFoo> fooPtr; //line#5
IFoo* fooPtr; //line#6
public:
/*Thud(std::shared_ptr<IFoo> fooPtr_) : fooPtr{ fooPtr_ }
{}*/ //line#7
Thud(IFoo* fooPtr_) : fooPtr{ fooPtr_ }
{} //line#8
bool thud1(bool b)
{
return fooPtr->Foo(b);
}
};
TEST_F(ThudTest, fooFalse)
{
bool b = false;
EXPECT_CALL(mock, Foo(b)).Times(1).WillOnce(Return(false));;
Thud thud(foo);
EXPECT_FALSE(thud.thud1(b));
}
TEST_F(ThudTest, fooTrue)
{
bool b = true;
EXPECT_CALL(mock, Foo(b)).Times(1).WillOnce(Return(true));;
Thud thud(foo);
EXPECT_TRUE(thud.thud1(b));
}
int main(int argc, char** argv) {
// The following line must be executed to initialize Google Mock
// (and Google Test) before running the tests.
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
所以为了完成,我有一个重载的构造函数,它不进行争论但会执行以下操作,
Thud():fooPtr {std::make_shared<FooImpl>()}
{}
在生产中得到真正的实现。 但是现在如何使指针指向模拟对象。如您所见,我在这里使用的是 GMock 框架。如何实现?
如果我注释掉使用普通旧原始指针的第 2、4、6 和 8 行,并取消注释并使用第 1、3、5 和 7 行(使用此处有问题的 shared_ptr
) 相反,它在第一个测试用例后因堆损坏而崩溃。
它与这个原始指针完美配合。
最佳答案
你不能做 foo.reset(&mock)
, 从那以后mock
有两个所有者:它的自动存储持续时间,加上共享指针 foo
.内存损坏 FTW。
您应该简单地分配 FooMock
动态并在创建 Thud
时传入正在测试的实例:
class ThudTest : public ::testing::Test
{
protected:
virtual void SetUp() {
foo = std::make_shared<FooMock>();
}
std::shared_ptr<FooMock> foo;
};
您甚至不需要 mock
成员(member)了。请注意,我已经更改了 foo
的类型了解FooMock
,以便您可以访问该类型。如果你真的想要foo
要保持模拟不知道,请这样做:
class ThudTest : public ::testing::Test
{
protected:
virtual void SetUp() {
mock = std::make_shared<FooMock>();
foo = mock;
}
std::shared_ptr<FooMock> mock;
std::shared_ptr<IFoo> foo;
};
但是,这不是必需的,因为 std::shared_ptr<FooMock>
可隐式转换为 std::shared_ptr<IFoo>
.
关于c++ - 如何使用 shared_ptr 从外部提供模拟对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47200078/