c++ 我可以在设定期望值后复制一个google mock对象吗?

fnatzsnv  于 2023-03-05  发布在  Go
关注(0)|答案(3)|浏览(110)

我想在我的测试fixture类中添加一个实用函数,它将返回一个带有特定期望/操作集的mock。
例如:

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的成员,而且由于只有一些测试使用那个特定的mock(并且我应该只在测试使用它时填充mock行为),所以它会不太干净。

vsnjm48y

vsnjm48y1#

模拟对象是不可复制的,但是你可以写一个工厂方法返回一个指向新创建的模拟对象的指针,为了简化对象的所有权,你可以使用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.
}
9ceoxa92

9ceoxa922#

好吧,似乎不可能正确地复制模拟类示例,尤其是不深度复制绑定到它们的任何期望。
您可以做的是,在测试类中提供helper函数,这些函数设置了对模拟示例的特定期望,例如:

class MyTest: public testing::Test {
public:
    MockListener& setSpecialListenerExpectations(MockListener& special) 
             // ^                                            ^
    {
        EXPECT_CALL(special, /** Some special behaviour e.g.  WillRepeatedly(Invoke( */ );
        return special;
    }
};

让它们在你的测试用例中变得特别

TEST_F(MyTest, MyTestUsingSpecialListener) {
    MockListener special;
    setSpecialListenerExpectations(special);

    // Do something with special.
}
gev0vcfq

gev0vcfq3#

不能创建可复制的模拟类,但可以编写可复制的类,该类引用提供其实现的模拟对象。

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);
}

注意,为了模拟的目的,在哪个示例/副本上调用模拟方法通常并不重要,因此使用单个(共享)模拟对象来模拟多个副本的行为通常是可以接受的。但是,当在共享一个实现对象的多个副本上调用时,必须注意调用的顺序......
这种方法还可以用于“跟踪”复制/移动构造/分配,并对是否/何时调用它们以及调用频率制定预期。

相关问题