如何使用gMock测试智能指针持有的多态接口类?
解决gMock测试多态注入对象的问题
核心问题排查与修复步骤
1. 确保Mock类定义完全符合gMock规则
你的MockDraw类必须严格匹配DrawI的接口签名,使用gMock的MOCK_METHOD宏声明所有虚函数(包括纯虚和非纯虚)。签名不匹配会导致gMock无法正确拦截方法调用。
正确的Mock类定义示例:
#include <gmock/gmock.h> struct MockDraw : public DrawI { // 匹配原接口的point方法(非纯虚也需Mock) MOCK_METHOD(void, point, (int x1, int y1), (override)); // 匹配原接口的纯虚line方法 MOCK_METHOD(void, line, (int x1, int y1, int x2, int y2), (override)); };
必须加上
override关键字确保签名完全匹配,gMock会严格检查方法的参数、返回值、const修饰符(若有)是否与原接口一致。
2. 验证DeviceIO内部是否正确持有并使用传入的DrawI实例
检查DeviceIO的实现,确保它没有在内部创建新的DrawI实例,而是直接使用构造函数传入的shared_ptr:
struct DeviceIO { std::shared_ptr<DrawI> _drawer; OtherProperties _props; DeviceIO(std::shared_ptr<DrawI> drawer, OtherProperties props) : _drawer(std::move(drawer)), _props(std::move(props)) {} void draw(Type t, Info i) { // 确保此处调用的是传入的_drawer实例的方法 if (t == Point) { _drawer->point(i.x, i.y); // 根据实际Info结构调整参数 } // 其他绘图逻辑... } // 其他方法... };
如果DeviceIO内部替换了_drawer指针,gMock的调用拦截自然不会生效。
3. 修正测试代码的细节
你的测试框架逻辑正确,但需注意两个关键细节:
EXPECT_CALL必须在调用io.draw()之前设置,gMock的调用期望是前置声明的。- 若需要精确匹配参数,可使用gMock的匹配器(如
Eq()),默认是宽松匹配任意参数。
修正后的测试代码:
TEST(DeviceIOTest, DrawPointTriggersMockCall) { // 创建Mock实例 auto painter = std::make_shared<MockDraw>(); // 注入到DeviceIO DeviceIO io(painter, {/* 初始化OtherProperties */}); // 设置期望:point方法被调用1次,参数为任意值 EXPECT_CALL(*painter, point(::testing::_, ::testing::_)).Times(1); // 执行被测试方法 EXPECT_NO_THROW(io.draw(Point, {/* 构造对应的Info对象 */})); }
常见坑点总结
- 签名不匹配:Mock方法的参数类型、返回值、const修饰符必须与原接口完全一致,否则gMock无法识别。
- 实例不唯一:确保DeviceIO使用的是你创建的Mock实例,而非内部新建的其他DrawI实现。
- 期望顺序错误:
EXPECT_CALL必须在触发调用的代码之前执行,否则gMock会判定期望未被满足。
内容的提问来源于stack exchange,提问作者Lorah Attkins
相关产品推荐
相关产品推荐

