如何避免向MOCK_METHOD内的MATCHER传递不可拷贝对象?
问题
尝试让MOCK_METHOD定义的BarClass::Bar方法抛出异常时,遇到编译错误:error: call to implicitly-deleted copy constructor of 'FooMock'。推测错误出在MATCHER_P内的==运算符处——MOCK_METHOD生成的数据成员不可拷贝,而BarClass::Bar接收FooMock的引用,无法改用指针。想知道能否向Matcher传递解引用后的对象?
代码示例:
class FooClass { public: virtual void Foo() const{} }; class FooMock : public FooClass { public: MOCK_METHOD(void, Foo, (), (const override)); }; struct BarClass { void Bar(const FooMock& fooMock) {} }; class BarMock : public BarClass { public: MOCK_METHOD(void, Bar, (FooMock& fooMock), (const override)); }; MATCHER_P(Matcher, fooMock, "") { return arg == fooMock; } ACTION(MyThrowException) { throw std::invalid_argument("Some exception thrown!"); } TEST(UtClass, Test) { auto fooMock = std::make_shared<FooMock>(); BarMock barMock; EXPECT_CALL(barMock, Bar (Matcher(*fooMock))) // <-- 问题处 .Times(1) .WillRepeatedly(MyThrowException()); barMock.Bar(*fooMock); // 预期抛出异常 }
解决方案
核心问题原因
MATCHER_P会拷贝传入的参数,而FooMock因包含GMock生成的不可拷贝成员(如内部mock控制结构),其拷贝构造函数被隐式删除,直接传递*fooMock会触发拷贝操作,导致编译错误。
可行解决方法
方法1:通过指针对比实例,避免拷贝
自定义Matcher时传入FooMock的指针,直接对比对象地址验证实例一致性,完全规避拷贝:
// 修改Matcher接收指针,对比对象地址 MATCHER_P(Matcher, fooMockPtr, "") { return &arg == fooMockPtr; } // EXPECT_CALL中直接传入指针 EXPECT_CALL(barMock, Bar (Matcher(fooMock.get()))) .Times(1) .WillRepeatedly(MyThrowException());
方法2:简化逻辑,直接验证异常
若核心需求仅为验证Bar调用时抛出异常,无需精确匹配FooMock实例,可简化为:
TEST(UtClass, Test) { auto fooMock = std::make_shared<FooMock>(); BarMock barMock; EXPECT_CALL(barMock, Bar (::_)) // 匹配任意FooMock引用 .Times(1) .WillOnce(MyThrowException()); // 直接验证调用是否抛出预期异常 ASSERT_THROW(barMock.Bar(*fooMock), std::invalid_argument); }
方法3:用Ref()包装传递引用
若必须传递对象实例而非指针,可使用GMock的::testing::Ref()包装参数,让Matcher接收引用而非拷贝:
// 修改Matcher接收const引用,按需编写对比逻辑 MATCHER_P(Matcher, fooMockRef, "") { return &arg == &fooMockRef; } // 使用Ref()包装避免拷贝 EXPECT_CALL(barMock, Bar (Matcher(::testing::Ref(*fooMock)))) .Times(1) .WillRepeatedly(MyThrowException());
额外修正点
原代码中BarMock的Bar方法签名违反C++重写规则:父类BarClass::Bar是void Bar(const FooMock&),子类BarMock的Bar却定义为void Bar(FooMock&),缺少const限定符,导致无法正确重写父类方法,需修正为:
class BarMock : public BarClass { public: MOCK_METHOD(void, Bar, (const FooMock& fooMock), (override)); };
内容的提问来源于stack exchange,提问作者xyf
相关产品推荐
相关产品推荐

