资讯详情

如何用 GoogleMock 验证 mock 对象的析构函数调用时机

📅 2026/9/12 13:02:58 | 华诺云谱 👁 阅读
如何用 GoogleMock 验证 mock 对象的析构函数调用时机
如何用 GoogleMock 验证 mock 对象的析构函数调用时机【免费下载链接】googletestGoogleTest - Google Testing and Mocking Framework项目地址: https://gitcode.com/GitHub_Trending/go/googletest在单元测试里你有时需要确认某个 mock 对象在正确的时间点被销毁例如验证被测代码在调用bar-A()之后、bar-B()之前释放了*foo这类所有权和生命周期逻辑。googletest 中的 GoogleMock 提供了针对 mock 函数调用顺序的约束机制但MOCK_METHOD宏无法直接作用于析构函数。本文给出项目文档中的标准做法把验证析构时机转换为验证一个普通 mock 方法的调用时机并用InSequence把它嵌入到调用顺序中做验证。为什么不能直接 mock 析构函数析构函数是特殊语法、特殊语义的函数MOCK_METHOD宏对它不工作下面的写法无法通过编译MOCK_METHOD(void, ~MockFoo, ()); // Wont compile!因此 GoogleMock 官方文档gmock_cook_book.md 的 Mocking Destructors 一节给出的替代方案是给 mock 类增加一个普通 mock 方法Die()并让析构函数调用它。这样测试对象何时被销毁就等价于测试Die()何时被调用而后者可以完全用EXPECT_CALL()加调用顺序约束来表达。前提被继承类的析构函数必须是 virtual在写 mock 之前先确认被 mock 接口的析构函数是虚函数。gmock_for_dummies.md 明确指出所有打算被继承的类其析构函数必须是virtual——否则通过基类指针delete对象时派生类的析构函数不会被调用会产生内存泄漏等状态损坏。gmock_faq.md 也把这一点列为排查项如果测试中出现 heapcheck failure而换成真实对象就没问题首先检查被 mock 的类是否有虚析构函数并把非虚的~Base()改为 virtual。文档同时说明如果你使用gtest_main库链接时会自动启用堆检查见下文验证结果。步骤一给 mock 类加 Die() 方法并让析构函数调用它按照 gmock_for_dummies.md 的常规流程写好 mock 类从接口派生、对每个要 mock 的虚函数写MOCK_METHOD之后只需在类里追加两行class MockFoo : public Foo { ... // Add the following two lines to the mock class. MOCK_METHOD(void, Die, ()); ~MockFoo() override { Die(); } };其中...代表你按常规流程为接口其他虚函数写好的 mock 方法MOCK_METHOD会自动生成定义不需要在别处再实现。如果Die()与现有符号重名文档说明换一个名字即可。步骤二用 InSequence 把 Die() 嵌入调用顺序GoogleMock 默认不要求调用按EXPECT_CALL()的书写顺序发生要让所有调用严格按顺序执行需要在代码块中定义一个InSequence变量块内的期望就构成一个序列乱序调用会由 gMock 直接报错参见 gmock_cook_book.md 的 Expecting Ordered Calls 一节。把Die()放进序列就能断言 mock 对象的销毁时机。以下测试来自文档原文MockFoo* foo new MockFoo; MockBar* bar new MockBar; ... { InSequence s; // Expects *foo to die after bar-A() and before bar-B(). EXPECT_CALL(*bar, A()); EXPECT_CALL(*foo, Die()); EXPECT_CALL(*bar, B()); }含义是*foo必须在bar-A()之后、bar-B()之前被析构。两个注意点mock 对象是在堆上分配的new MockFoo。文档提示如果 mock 对象从未被 delete最终的期望验证就不会发生因此堆上分配 mock 时建议开启堆检查链接gtest_main会自带该检查gmock_for_dummies.md Using Mocks in Tests 一节。gMock 要求所有期望在被 mock 函数被调用之前设置好不要在调用EXPECT_CALL()和调用 mock 函数之间交替进行也不要在把 mock 传给被测 API 之后再补设期望否则行为未定义。验证结果按 quickstart-cmake.md 的方式配置你的测试工程至少需要支持 C17 的编译器与 CMake 及构建工具通过FetchContent引入 googletest 并链接测试主库构建并运行测试后验证分两层顺序断言如果Die()没有落在A()和B()之间即 mock 对象的析构时机不对gMock 会按乱序调用立即报告错误。析构时的自动校验GoogleMock 的工作流程规定当 mock 对象被析构时会自动检查其上的所有期望是否都已满足gmock_for_dummies.md Using Mocks in Tests 第 5 步。例如若Die()从未发生期望计数不匹配会输出类似下面的失败信息以下为文档示例输出path/to/my_test.cc:119: Failure Actual function call count doesnt match this expectation: Actually: never called; Expected: called at least once. Stack trace: ...测试全部通过即说明mock 对象在期望的时间窗口内被析构且其上设置的期望都被满足。限制与边界Die()只是析构的代理信号验证的是析构函数被调用这一时机无法表达析构内部的行为细节。若使用NiceMockT/StrictMockT文档提示当T的析构函数不是 virtual 时它们可能无法正常工作reference/mocking.md。这与前文基类析构必须 virtual的要求一致。InSequence会强制序列内所有期望严格有序如果只关心部分调用的相对顺序可改用 Partial Order 一节介绍的Sequence/After()机制避免测试过于脆弱。参考文档gmock_cook_book.md、gmock_for_dummies.md、gmock_faq.md、quickstart-cmake.md。【免费下载链接】googletestGoogleTest - Google Testing and Mocking Framework项目地址: https://gitcode.com/GitHub_Trending/go/googletest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。