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

Mock Ctrl::Do抛出异常时调用计数不匹配问题排查

GMock测试问题解答

问题背景

想要Mock Ctrl类的Do(const Handler& handler)方法使其抛出异常。Ctrl类持有Handler的std::weak_ptr,在Handling方法中会调用Do(*handlerSptr),但运行测试时出现GMOCK错误:实际调用次数与EXPECT_CALL预期不匹配,提示函数调用不匹配。同时存在三个疑问:

  1. HandlerMock是Handler的子类,为何会出现函数匹配问题?
  2. MATCHER未触发Handler的==运算符,是否正常?
  3. 能否仅在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 03:15:38