You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免向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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 23:50:28