news 2026/9/12 16:48:50

如何用 GoogleMock NiceMock 和 StrictMock 控制 uninteresting call 警告

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何用 GoogleMock NiceMock 和 StrictMock 控制 uninteresting call 警告

如何用 GoogleMock NiceMock 和 StrictMock 控制 uninteresting call 警告

【免费下载链接】googletestGoogleTest - Google Testing and Mocking Framework项目地址: https://gitcode.com/GitHub_Trending/go/googletest

在写 GoogleMock 测试时,一个常见的现象是:mock 对象的某个方法没有设置任何EXPECT_CALL,却仍然被被测代码调用了。gMock 把这种调用称为 uninteresting call,默认的 mock 对象(行为等价于NaggyMock)会执行该方法的默认动作(可用ON_CALL()指定),并额外打印一条 "uninteresting" 警告。这条警告本身不是错误,但有时你希望彻底静默它,有时又希望它直接让测试失败。本文基于 GoogleMock 实战手册 和 参考文档,说明如何分别用NiceMock<T>StrictMock<T>来控制这两类行为,以及各自的适用边界。

动手前先分清 uninteresting call 和 unexpected call

这两种调用在 gMock 中是完全不同的概念(见 The Nice, the Strict, and the Naggy 一节的解释):

  • uninteresting call:方法x.Y(...)一个EXPECT_CALL(x, Y(...))都没有设置,说明测试对该方法本身不关心。按 gMock 的规则,"不说什么"就意味着"没有约束",所以 uninteresting call 默认不是错误,只产生警告——因为可能暗示测试作者忘了写约束。
  • unexpected call:已经设置了某些EXPECT_CALL(x, Y(...)),但没有一个与本次调用匹配。unexpected call总是错误,因为被测代码的行为不符合测试预期。

NiceMockStrictMock只作用于 uninteresting call,不影响 unexpected call 的严重级别。这一点直接决定了后文两种包装的用法:nice mock 不会让原本失败的测试通过,strict mock 则可能改变测试结果。

用 NiceMock 静默 uninteresting call 警告

NiceMock<T>表示一个会对 uninteresting call 抑制警告的 mock 对象(见 NiceMock 参考条目)。它是T的子类,可以放在任何接受T的地方使用;同时它"继承"了T的构造函数,所以可以接受T构造函数所需的任意实参。

假设测试原本这样写:

TEST(...) { MockFoo mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... }

只要mock_fooDoThis()之外的方法被调用,就会收到警告。改用NiceMock<MockFoo>即可抑制这类警告:

using ::testing::NiceMock; TEST(...) { NiceMock<MockFoo> mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... }

如果MockFoo的构造函数需要参数,直接透传即可:

using ::testing::NiceMock; TEST(...) { NiceMock<MockFoo> mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... }

替代路径:如果你只想对个别方法关闭警告,而不想静默整个 mock 对象,手册给出的做法是为该方法补一条EXPECT_CALL(...).Times(AnyNumber()),例如:

using ::testing::_; using ::testing::AnyNumber; EXPECT_CALL(mock_registry, GetDomainOwner(_)) .Times(AnyNumber()); // catches all other calls to this method.

手册同时明确警告:不要为了消除警告而盲目地加EXPECT_CALL(...)(不带Times(AnyNumber())),那会造出一个难以维护的测试。

判断依据:手册指出,nice mock 只是"话少"了,除此之外与默认 mock 行为一致——如果某个测试用默认 mock 会失败,换成 nice mock 一样会失败,反之亦然。所以验证NiceMock是否生效,看的是警告消失且测试结果不变,而不是测试结果发生变化。

用 StrictMock 把 uninteresting call 变成失败

StrictMock<T>的用法与NiceMock<T>类似(见 StrictMock 参考条目),区别是它把所有 uninteresting call 从警告升级为测试失败:

using ::testing::StrictMock; TEST(...) { StrictMock<MockFoo> mock_foo; EXPECT_CALL(mock_foo, DoThis()); ... code that uses mock_foo ... // The test will fail if a method of mock_foo other than DoThis() // is called. }

只要被测代码调用了mock_foo上除DoThis()之外的任何方法,测试就会失败。与 nice mock 不同,手册明确指出:把 mock 改成 strict 可能会改变测试结果,这正是使用它的目的,也是使用它需要小心的原因。

一个典型的配合场景来自手册中"uninteresting vs unexpected"一节:只想验证GetDomainOwner("google.com")的行为,但允许该方法用其他参数被调用。标准做法是加一条"兜底"EXPECT_CALL

EXPECT_CALL(mock_registry, GetDomainOwner(_)) .Times(AnyNumber()); // catches all other calls to this method. EXPECT_CALL(mock_registry, GetDomainOwner("google.com")) .WillRepeatedly(Return("Larry Page"));

注意两条EXPECT_CALL的先后顺序很重要:新写的EXPECT_CALL优先于旧写的生效。这里_是匹配任意值的通配 matcher——GetDomainOwner("google.com")命中第二条,其余参数命中第一条。

必须了解的三个限制

NiceMockStrictMock都有一些 C++ 层面带来的限制,使用前的 mock 类设计要对照检查:

  1. 只对被测类内直接用MOCK_METHOD宏定义的 mock 方法生效。如果 mock 方法定义在T的基类中,"nice"或"strict"修饰对它们可能不起作用,具体取决于编译器。
  2. 不支持嵌套NiceMock<StrictMock<MockFoo>>这类嵌套写法不被支持。参考文档也相应限制:NiceMock<T>NaggyMock<T>StrictMock<T>的模板参数T不能是另一个NiceMockNaggyMockStrictMock
  3. T的析构函数如果不是 virtual,修饰可能不生效,文档明确说明这一点是已知的局限。

什么时候选哪种

手册对选择给出了明确的倾向性建议,可以直接对照执行:

  • naggy mock(当前默认):在开发或调试测试时使用,警告加默认行为帮你留意"是否有该设约束而未设约束的调用"。
  • nice mock:多数时候使用,避免重构代码时因内部交互变化被警告刷屏。
  • strict mock:只作为最后手段。

原因是 naggy 或 strict mock 倾向让测试更脆、更难维护:当你重构代码而不改变外部可见行为时,理想情况下测试不该跟着改;但代码一旦与 naggy mock 交互,可能开始被警告刷屏,与 strict mock 交互则测试直接失败、被迫修改。

验证与后续排查

仓库自带针对该行为的测试文件 gmock-nice-strict_test.cc,可以结合它观察三种 mock 在相同调用序列下的表现差异。日常验证时可以按上面的判断依据对照:

  • 换成NiceMock后,uninteresting call 警告消失,测试结果与原 mock 一致;
  • 换成StrictMock后,故意触发一条未设EXPECT_CALL的调用,测试应当失败;
  • 若仍看到 "Uninteresting function call encountered - default action taken.." 之类的警告,gmock_faq.md 解释它只是提示信息而非错误:gMock 遇到 uninteresting call 时会 dump 调用栈,从中可以定位是哪个 mock 方法、被怎样调用的。如果认为本不该出现 uninteresting call,应顺着调用栈排查;如果你本意是禁止调用却忘了写EXPECT_CALL(foo, Bar()).Times(0),按 Disallowing Unexpected Calls 一节补上显式的Times(0)约束,而不是靠包装类兜底。

限制方面再强调一次:以上所有行为只针对方法上没有任何EXPECT_CALL的 uninteresting call;已经设置了EXPECT_CALL但参数不匹配的 unexpected call 始终是错误,NiceMock也不会减轻它的严重级别。

【免费下载链接】googletestGoogleTest - Google Testing and Mocking Framework项目地址: https://gitcode.com/GitHub_Trending/go/googletest

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 16:42:26

AI驱动的论文写作工具:技术解析与应用实践

1. 项目概述&#xff1a;AI驱动的论文写作革命"书匠策AI"作为一款智能数据分析导航工具&#xff0c;正在重新定义学术写作的边界。这个系统通过自然语言处理、机器学习和大数据分析技术的深度融合&#xff0c;为研究者构建了一个从选题挖掘到论文成稿的智能写作支持平…

作者头像 李华
网站建设 2026/9/12 16:39:57

如何给老Mac安装新版macOS:OpenCore Legacy Patcher 2.5.0完整指南

如何给老Mac安装新版macOS&#xff1a;OpenCore Legacy Patcher 2.5.0完整指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 当你想升级系统、却发现"…

作者头像 李华
网站建设 2026/9/12 16:39:12

Supermemory v0.0.5 精确文本搜索返回空结果怎么解决

Supermemory v0.0.5 精确文本搜索返回空结果怎么解决 【免费下载链接】supermemory Memory and context engine app that is extremely fast, scalable, and can be run fully locally. The Memory API for the AI era. 项目地址: https://gitcode.com/GitHub_Trending/su/s…

作者头像 李华
网站建设 2026/9/12 16:37:11

ToolJet 3.0.0-LTS PostgreSQL 数据源接入与查询实战指南

ToolJet 3.0.0-LTS PostgreSQL 数据源接入与查询实战指南 【免费下载链接】ToolJet Open-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from…

作者头像 李华