我可以在设置期望后复制一个谷歌模拟对象吗?

问题描述 投票:0回答:3

我想在我的测试夹具类中添加一个实用函数,它将返回一个具有特定期望/操作集的模拟。

例如:

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 的成员,并且因为只有一些测试使用那个特定的模拟(如果测试正在使用它,我应该只填充模拟行为)它会不太干净。

c++ unit-testing googletest googlemock
3个回答
3
投票

模拟对象是不可复制的,但你可以编写一个工厂方法,返回一个指向新创建的模拟对象的指针。为了简化对象所有权,您可以使用

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.
}

1
投票

好吧,似乎不可能正确复制模拟类实例,尤其是不能深度复制任何绑定到它们的期望。

你可以做的是,在你的测试类中提供辅助函数,对模拟实例设置特定的期望,比如:

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.
}

0
投票

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

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

请注意,出于模拟的目的,在哪个实例/副本上调用模拟方法通常甚至无关紧要,因此使用单个(共享)模拟对象来模拟多个副本的行为通常是可以接受的。但是,当它们在多个副本上共享一个实现对象时,必须注意调用的顺序......

这种方法也可用于“跟踪”复制/移动构造/分配,并制定关于是否/何时以及多久调用它们的期望。

© www.soinside.com 2019 - 2024. All rights reserved.