Mock Ctrl::Do抛出异常时调用计数不匹配问题排查
GMock测试问题解答
问题背景
想要Mock Ctrl类的Do(const Handler& handler)方法使其抛出异常。Ctrl类持有Handler的std::weak_ptr,在Handling方法中会调用Do(*handlerSptr),但运行测试时出现GMOCK错误:实际调用次数与EXPECT_CALL预期不匹配,提示函数调用不匹配。同时存在三个疑问:
- HandlerMock是Handler的子类,为何会出现函数匹配问题?
- MATCHER未触发Handler的
==运算符,是否正常? - 能否仅在HandlerMock中实现
==运算符而非在Handler类中(该运算符仅为测试添加)?
问题分析与解答
1. 子类HandlerMock的函数匹配问题
GMock默认严格匹配参数的静态类型和值语义。虽然HandlerMock是Handler的子类,但Ctrl的Do方法接收的是const Handler&类型参数,当EXPECT_CALL直接传入HandlerMock对象时,会发生对象切片:实际传递给Do的是基类Handler的部分,GMock会按基类类型去匹配,导致匹配失败。
解决办法:
- 使用GMock的
Ref()匹配器,明确匹配引用类型:EXPECT_CALL(ctrlMock, Do(Ref(handlerMock))) .WillOnce(Throw(std::runtime_error("test exception"))); - 或者自定义
Matcher<const Handler&>,通过dynamic_cast判断参数是否为HandlerMock实例,实现类型匹配。
2. MATCHER未触发==运算符是否正常
正常。GMock的MATCHER机制不会自动调用类的==运算符,除非你明确指定:
- 只有使用
Eq()匹配器时(比如EXPECT_CALL(ctrlMock, Do(Eq(handlerMock)))),才会触发Handler类的==运算符; - 直接传对象时,GMock会对引用类型比较内存地址,对值类型按字节比较,不会调用自定义
==。
3. 仅在HandlerMock中实现==运算符的可行性
可以,但需要注意匹配逻辑的正确性:
- 如果基类Handler没有定义
==运算符,编译器会使用默认逐成员比较;若基类有==,则会优先调用基类版本(因为operator==默认不是虚函数,无法触发多态)。 - 更干净的方案是自定义GMock匹配器,完全在测试代码中实现匹配逻辑,不污染生产代码:
MATCHER_P(IsHandlerMockEqualTo, expected, "") { const auto* actualMock = dynamic_cast<const HandlerMock*>(&arg); return actualMock != nullptr && *actualMock == expected; } // 使用示例 EXPECT_CALL(ctrlMock, Do(IsHandlerMockEqualTo(handlerMock))) .WillOnce(Throw(std::runtime_error("test exception")));
补充建议
如果Ctrl类的Do方法参数是const Handler&,实际传递的是HandlerMock引用,一定要用Ref()或自定义匹配器处理引用类型,避免切片导致的匹配失败。同时确保GMock匹配器的类型与函数参数类型严格一致。
内容的提问来源于stack exchange,提问作者xyf
相关产品推荐
相关产品推荐

