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

如何用旧版gmock模拟被派生类重载的基类虚方法?

问题描述

我正尝试使用旧版gmock模拟基类的一个虚方法,该方法实现了一些基础功能,且被派生类的重载版本调用。

我编写的代码如下:

class BaseFoo
{
public:
    virtual bool init()
    {
        std::cout << "Some basic functionality" << std::endl;
        return true;
    }
};

class Foo : public BaseFoo
{
public:
    bool init() override
    {
        if (!BaseFoo::init())
            return false;
            
        std::cout << "Some additional functionality" << std::endl;
        
        return true;
    }
};

class MockFoo : public Foo
{
public:
    MOCK_METHOD0(BaseFoo::init, bool());
};

TEST(FooTests, InitTest)
{
    Foo f;
    bool result = false;
    
    EXPECT_CALL(f, BaseFoo::init).WillOnce(testing::Return(true));
    
    result = f.init();
    
    ASSERT_TRUE(result);
}

运行后遇到的错误:

error: cannot define member function 'BaseFoo::init' within 'MockFoo'
     MOCK_METHOD0(BaseFoo::init, bool());
     ^
error: 'gmock_BaseFoo' has not been declared
     MOCK_METHOD0(BaseFoo::init, bool());
     ^
error: 'gmock0_BaseFoo' has not been declared
     MOCK_METHOD0(BaseFoo::init, bool());
     ^
error: conflicting return type specified for 'virtual testing::internal::MockSpec<bool()>& MockFoo::init()'
     MOCK_METHOD0(BaseFoo::init, bool());
     ^
error:   overriding 'virtual bool Foo::init()'
     bool init() override
     ^
error: 'gmock0_BaseFoo' has not been declared
     MOCK_METHOD0(BaseFoo::init, bool())
     ^
error: 'gmock0_BaseFoo' has not been declared
     MOCK_METHOD0(BaseFoo::init, bool());
     ^
error: 'Foo::gmock_BaseFoo' has not been declared
     EXPECT_CALL(f, BaseFoo::init).WillOnce(testing::Return(true));
     ^

我的目标是模拟该基类方法,以便在测试中能够预期它的调用。请问是否有可行的实现方式?

可行实现方式

方法1:重构Foo为模板类,替换基类为Mock版本

通过将Foo改为模板类,测试时可替换其基类为Mock版本,从而捕获基类init()的调用:

// 重构Foo为模板类,默认使用原BaseFoo
template<typename Base = BaseFoo>
class Foo : public Base
{
public:
    bool init() override
    {
        if (!Base::init())
            return false;
            
        std::cout << "Some additional functionality" << std::endl;
        
        return true;
    }
};

// 定义BaseFoo的Mock类
class MockBaseFoo : public BaseFoo
{
public:
    MOCK_METHOD0(init, bool());
};

// 测试用例
TEST(FooTests, InitTest)
{
    Foo<MockBaseFoo> f;
    bool result = false;
    
    EXPECT_CALL(f, init()).WillOnce(testing::Return(true));
    
    result = f.init();
    
    ASSERT_TRUE(result);
}

这种方式无需修改原有业务逻辑的核心,仅通过模板化实现测试时的基类替换。

方法2:在MockFoo中重写init,转发到Mock方法

如果无法修改原Foo结构,可在MockFoo中重写init(),将对BaseFoo::init()的调用替换为Mock方法:

class MockFoo : public Foo
{
public:
    // 定义模拟基类init的Mock方法
    MOCK_METHOD0(mock_base_init, bool());
    
    bool init() override
    {
        // 用Mock方法替代原BaseFoo::init()
        if (!mock_base_init())
            return false;
            
        // 保留Foo原本的额外逻辑
        std::cout << "Some additional functionality" << std::endl;
        
        return true;
    }
};

TEST(FooTests, InitTest)
{
    MockFoo f;
    bool result = false;
    
    EXPECT_CALL(f, mock_base_init()).WillOnce(testing::Return(true));
    
    result = f.init();
    
    ASSERT_TRUE(result);
}

该方案无需改动原业务代码,仅通过Mock类的重写逻辑实现调用预期。

错误原因说明

原代码的核心问题:

  • MOCK_METHOD0(BaseFoo::init, bool())写法错误:gmock的Mock宏仅能声明当前类的成员方法,不能直接指定基类方法名。
  • 测试用例使用了普通Foo对象而非MockFoo对象:只有Mock类实例才能被EXPECT_CALL捕获调用。

内容的提问来源于stack exchange,提问作者Tailwhip

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 09:05:38