如何用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
相关产品推荐
相关产品推荐

