我想在我的测试夹具类中添加一个实用函数,它将返回一个具有特定期望/操作集的模拟。
例如:
class MockListener: public Listener
{
// Google mock method.
};
class MyTest: public testing::Test
{
public:
MockListener getSpecialListener()
{
MockListener special;
EXPECT_CALL(special, /** Some special behaviour e.g. WillRepeatedly(Invoke( */ );
return special;
}
};
TEST_F(MyTest, MyTestUsingSpecialListener)
{
MockListener special = getSpecialListener();
// Do something with special.
}
不幸的是我得到:
error: use of deleted function ‘MockListener ::MockListener (MockListener &&)’
所以我假设模拟不能被复制?为什么,如果有的话,还有另一种优雅的方法来获得一个函数来制造一个已经设置好期望/动作的现成模拟吗?
很明显,我可以让 getSpecialListener 返回一个 MockListener&,但是这样它就不需要成为 MyTest 的成员,并且因为只有一些测试使用那个特定的模拟(如果测试正在使用它,我应该只填充模拟行为)它会不太干净。
模拟对象是不可复制的,但你可以编写一个工厂方法,返回一个指向新创建的模拟对象的指针。为了简化对象所有权,您可以使用
std::unique_ptr
.
std::unique_ptr<MockListener> getSpecialListener() {
MockListener* special = new MockListener();
EXPECT_CALL(*special, SomeMethod()).WillRepeatedly(DoStuff());
return std::unique_ptr<MockListener>(special);
}
TEST_F(MyTest, MyTestUsingSpecialListener) {
std::unique_ptr<MockListener> special = getSpecialListener();
// Do something with *special.
}
好吧,似乎不可能正确复制模拟类实例,尤其是不能深度复制任何绑定到它们的期望。
你可以做的是,在你的测试类中提供辅助函数,对模拟实例设置特定的期望,比如:
class MyTest: public testing::Test {
public:
MockListener& setSpecialListenerExpectations(MockListener& special)
// ^ ^
{
EXPECT_CALL(special, /** Some special behaviour e.g. WillRepeatedly(Invoke( */ );
return special;
}
};
并在您的测试用例中使它们 special:
TEST_F(MyTest, MyTestUsingSpecialListener) {
MockListener special;
setSpecialListenerExpectations(special);
// Do something with special.
}
您不能创建可复制的模拟类,但您可以编写一个可复制的类并引用提供其实现的模拟对象。
class MyMockImpl
{
public:
MOCK_METHOD(void, someMethod, (int arg), (const));
};
template<typename Impl>
class MyCopyableMock
{
public:
explicit MyCopyableMock(Impl& impl)
: impl(impl)
{}
void someMethod(int arg) const
{
impl.someMethod(arg);
}
};
TEST(CopyableMockTest, someMethod_isCalled)
{
MyMockImpl impl_mock;
MyCopyableMock<MyMockImpl> mock(impl_mock);
EXPECT_CALL(impl_mock, someMethod(123)).Times(Exactly(1));
MyCopyableMock copyMock = mock;
copyMock.someMethod(123);
}
请注意,出于模拟的目的,在哪个实例/副本上调用模拟方法通常甚至无关紧要,因此使用单个(共享)模拟对象来模拟多个副本的行为通常是可以接受的。但是,当它们在多个副本上共享一个实现对象时,必须注意调用的顺序......
这种方法也可用于“跟踪”复制/移动构造/分配,并制定关于是否/何时以及多久调用它们的期望。