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

如何用GTest/GMock测试调用保护成员方法的Memory类GetBlockList?

GTest/GMock测试Memory类GetBlockList方法的解决方案

方案一:重构代码实现依赖注入(推荐)

这种方式通过让Memory类的Block依赖可外部传入,从根源解决Mock访问问题,同时优化代码设计。

1. 修改Memory类的定义

调整Memory.h,将Block成员改为指针(或智能指针),并提供带参数的构造函数用于注入依赖:

// Memory.h
#include "Block.h"

namespace User{

class Memory
{
protected:
    Block* block_ptr;

public:
    // 测试专用构造:注入外部Block(含Mock对象)
    explicit Memory(Block* block) : block_ptr(block) {}
    // 原有构造逻辑,保持兼容
    Memory() : block_ptr(new Block()) {}
    // 注意内存管理,用智能指针可避免手动delete
    ~Memory() { delete block_ptr; }

    const BlockList* GetBlockList();
};

}

更新Memory.cpp的方法实现:

// Memory.cpp
#include "Memory.h"

namespace User{
const BlockList* Memory::GetBlockList()
{
    return block_ptr->GetList();
}
}

2. 定义MockBlock类

创建模拟Block类,覆盖虚函数GetList(需确保原Block类的GetList是虚函数):

// MockBlock.h
#include <gmock/gmock.h>
#include "Block.h"

namespace User{

class MockBlock : public Block {
public:
    MOCK_METHOD(const BlockList*, GetList, (), (override));
};

}

3. 编写测试用例

// MemoryTest.cpp
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "Memory.h"
#include "MockBlock.h"

using namespace User;
using ::testing::Return;

TEST(MemoryTest, GetBlockList_ReturnsBlockListFromInjectedBlock) {
    // 准备Mock对象和测试数据
    MockBlock mock_block;
    BlockList test_list;

    // 设置Mock调用期望:调用GetList时返回指定的BlockList
    EXPECT_CALL(mock_block, GetList())
        .WillOnce(Return(&test_list));

    // 创建Memory对象,注入MockBlock
    Memory memory(&mock_block);

    // 验证方法返回值符合预期
    EXPECT_EQ(memory.GetBlockList(), &test_list);
}

方案二:不修改原代码,通过派生类访问protected成员(限Block为多态、成员为指针/引用场景)

如果无法修改原Memory类,需满足两个前提:原Block类的GetList是虚函数,且Memory中的Block成员是指针/引用(否则会发生对象切片,Mock失效)。

1. 定义测试专用派生类

通过派生Memory类,暴露protected成员的访问权限:

// MemoryTest.cpp 中定义
namespace User{

class TestableMemory : public Memory {
public:
    // 替换内部的Block指针为Mock对象
    void SetBlock(Block* block) {
        // 原Memory的Block成员需为指针才能替换,否则此方法无效
        block_ptr = block;
    }
};

}

2. 编写测试用例

TEST(MemoryTest, GetBlockList_ReturnsMockedBlockList) {
    TestableMemory test_memory;
    MockBlock mock_block;
    BlockList test_list;

    EXPECT_CALL(mock_block, GetList())
        .WillOnce(Return(&test_list));

    test_memory.SetBlock(&mock_block);
    EXPECT_EQ(test_memory.GetBlockList(), &test_list);
}

方案三:使用测试友元(不推荐,破坏封装)

仅当完全无法修改原代码结构,且无需Mock仅验证原有逻辑时使用。需在Memory类中添加测试友元声明:

// Memory.h
namespace User{

class Memory
{
protected:
    Block block_instance;

public:
    const BlockList* GetBlockList();

    // 允许测试类访问protected成员
    friend class MemoryTest;
};

}

但注意:由于block_instance是Block对象而非指针,无法替换为MockBlock(会切片),因此此方式只能用于验证原Block的真实行为,无法实现Mock。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 14:34:52