Google Mock(简称 GMock)是与 Google Test(GTest)配套的模拟框架,主要用于解决单元测试中 “被测试代码依赖外部组件(如其他模块、硬件接口、网络服务等)” 的问题。它的核心功能是创建 “模拟对象(Mock Object)”,通过定义 “期望的交互行为” 来隔离被测试代码与外部依赖,让测试更聚焦于被测试模块的逻辑正确性。
一、GMock 的核心功能:解决 “依赖隔离” 问题
在单元测试中,被测试的代码(如 SSD 固件中的 “坏块管理模块”)往往依赖其他组件(如 “NAND 闪存接口模块”)。如果这些依赖组件:
尚未开发完成(如 NAND 驱动还在调试);
难以构造或控制(如真实 NAND 的硬件状态不可控);
操作耗时或不稳定(如读写真实 NAND 的耗时会干扰测试效率);
此时,直接使用真实依赖会导致测试难以编写、执行缓慢或结果不稳定。GMock 通过模拟这些依赖组件,让被测试代码 “以为” 在和真实组件交互,实则在与模拟对象交互,从而实现 “隔离依赖、专注逻辑” 的测试目标。
二、GMock 的关键能力与概念
- 定义 “模拟对象”(Mock Object)
模拟对象是对真实依赖组件的 “高仿”:它实现了与真实组件相同的接口(如 NAND 接口的read_block、write_page方法),但内部逻辑是 “可定制的”(由测试用例控制)。
例如,在 SSD 固件测试中,为 NAND 接口创建模拟对象:
cpp
运行
// 真实NAND接口(抽象类/纯虚函数)
class NandInterface {
public:
virtual ~NandInterface() = default;
virtual int read_block(uint32_t block_id, char* data) = 0; // 读块接口
virtual int write_page(uint32_t page_id, const char* data) = 0; // 写页接口
};
// 用GMock创建模拟对象(继承真实接口,并用MOCK_METHOD定义模拟方法)
class MockNand : public NandInterface {
public:
// 模拟read_block方法:参数类型、返回值需与真实接口一致
MOCK_METHOD2(read_block, int(uint32_t block_id, char* data));
// 模拟write_page方法
MOCK_METHOD2(write_page, int(uint32_t page_id, const char* data));
};
2. 设定 “期望”(Expectations)
通过 GMock 的宏(如EXPECT_CALL)定义 “被测试代码应该如何调用模拟对象的方法”,包括:
调用哪些方法;
传入什么参数;
调用多少次;
返回什么结果(或抛出什么异常)。
例如,测试 “坏块管理模块” 时,期望它会先调用read_block检查块 0 是否为坏块,并让模拟对象返回 “块 0 是坏块”:
cpp
运行
TEST(BadBlockMgrTest, CheckBadBlock) {
MockNand mock_nand; // 创建模拟NAND对象
BadBlockMgr mgr(&mock_nand); // 被测试的坏块管理器,依赖模拟NAND
// 设定期望:mgr会调用mock_nand的read_block,参数为block_id=0,且只调用1次
// 当调用发生时,让mock_nand返回1(表示“坏块”)
EXPECT_CALL(mock_nand, read_block(0, testing::_))
.Times(1)
.WillOnce(Return(1));
// 执行被测试逻辑:检查块0是否为坏块
bool is_bad = mgr.check_block(0);
// 断言结果:期望块0被判定为坏块
EXPECT_TRUE(is_bad);
}
这里的testing::表示 “任意参数”(忽略data指针的具体值),Times(1)要求方法必须被调用 1 次,WillOnce(Return(1))指定调用后返回 1。
3. 验证 “交互是否符合期望”
GMock 会自动记录模拟对象的方法调用情况,在测试结束时(如TEST函数退出时)验证:
所有EXPECT_CALL设定的期望是否被满足(如方法是否按预期次数调用、参数是否匹配);
是否有 “未被期望的调用”(如被测试代码意外调用了write_page,而测试用例未定义此期望)。
如果验证失败,测试会报错并提示具体原因(如 “read_block(0, …)被调用了 0 次,预期 1 次”)。
4. 灵活控制模拟对象的行为
GMock 支持复杂的行为定制,例如:
多次调用同一方法时返回不同结果(WillRepeatedly、WillOnce+WillOnce);
根据输入参数返回不同值(WithArgs结合Return);
模拟耗时操作(通过自定义Action);
抛出异常(WillOnce(Throw(std::runtime_error(“timeout”))))。
例如,模拟 NAND 读块时 “前 2 次超时,第 3 次成功”:
cpp
运行
EXPECT_CALL(mock_nand, read_block(5, testing::))
.Times(3)
.WillOnce(Throw(std::runtime_error(“timeout”))) // 第1次调用:抛超时异常
.WillOnce(Throw(std::runtime_error(“timeout”))) // 第2次调用:抛超时异常
.WillOnce(Return(0)); // 第3次调用:返回0(成功)
三、GMock 与 GTest 的关系
GTest:是单元测试框架,负责组织测试用例(TEST/TEST_F)、提供断言(EXPECT_EQ/ASSERT_TRUE等)、运行测试并生成报告。
GMock:是模拟框架,依赖 GTest 的断言机制,专注于创建模拟对象、定义交互期望、验证依赖调用。
两者通常一起使用:用 GMock 解决依赖隔离问题,用 GTest 组织用例和断言结果,共同构成完整的单元测试方案。
四、在 SSD 固件开发中的典型应用
SSD 固件的核心模块(如 FTL、ECC、坏块管理)往往依赖硬件接口(NAND 控制器、PCIe 寄存器、电源管理芯片等),GMock 的价值尤为突出:
测试ECC 纠错模块时,用MockNand模拟 “读页时返回带错误的数据”,验证 ECC 是否能正确纠错,无需真实 NAND 硬件;
测试FTL 地址映射模块时,用MockNand模拟 “写页失败”,验证 FTL 是否会触发重试或切换备用块;
测试NVMe 协议解析模块时,用MockHostInterface模拟 “主机发送非法命令”,验证固件是否能返回正确的错误码(如0x0002)。
简言之,GMock 是单元测试中 “隔离外部依赖” 的利器,它让开发者能在 “纯净环境” 中测试代码逻辑,尤其适合 SSD 固件这类强依赖硬件、场景复杂的嵌入式开发领域。
1878

被折叠的 条评论
为什么被折叠?



