如何在Google Mock中验证delete[]是否被正确调用
针对freeMemory函数的Google Test验证方案
要验证delete[]被正确调用,不需要复杂的mock逻辑,核心思路是拦截全局数组释放操作做计数校验,以下是可直接落地的方案:
方案1:重写全局operator delete[]做无侵入校验(推荐)
C++中基础类型(比如你代码里的char*)的delete[]调用最终都会走到全局operator delete[],不需要修改任何生产代码,只需要在测试代码中重写该函数,记录调用次数和被释放的指针,即可完成校验。
实现步骤
- 在测试文件中定义全局变量记录调用信息
- 重写全局
operator delete[],先记录调用参数,再执行真正的内存释放 - 每个测试用例执行前重置计数,构造符合要求的测试内存块传入待测试函数
- 校验调用次数、被释放指针是否和预期一致
测试代码示例
#include <gtest/gtest.h> #include <cstdlib> #include <cstring> // 测试用全局计数变量 constexpr size_t kMaxDeleteRecord = 10; size_t g_delete_array_call_cnt = 0; void* g_deleted_ptr_records[kMaxDeleteRecord] = {nullptr}; // 重写全局数组版本delete,符合C++标准签名 void operator delete[](void* ptr) noexcept { if (g_delete_array_call_cnt < kMaxDeleteRecord) { g_deleted_ptr_records[g_delete_array_call_cnt] = ptr; } g_delete_array_call_cnt++; // 必须调用free执行真正释放,避免测试本身泄漏/崩溃 free(ptr); } // 兼容部分编译器要求的带长度参数的delete[]版本,直接转发即可 void operator delete[](void* ptr, size_t) noexcept { operator delete[](ptr); } TEST(FreeMemoryTest, DeleteArrayCallIsCorrect) { // 每个用例执行前重置计数,避免用例间干扰 g_delete_array_call_cnt = 0; memset(g_deleted_ptr_records, 0, sizeof(g_deleted_ptr_records)); // 构造和函数逻辑匹配的测试内存:二级指针指向5个char数组 char** test_block = new char*[5]; for (int i = 0; i < 5; i++) { test_block[i] = new char[16]; // 分配长度任意,不影响释放逻辑 } // 记录预期会被释放的6个指针:5个一级数组 + 1个二级指针本身 void* expected_ptrs[6]; for (int i = 0; i < 5; i++) { expected_ptrs[i] = test_block[i]; } expected_ptrs[5] = test_block; // 执行待测试函数 freeMemory(test_block); // 校验1:delete[]总共调用6次,不多不少 ASSERT_EQ(g_delete_array_call_cnt, 6); // 校验2:所有预期的指针都被释放,没有漏释放、错释放 for (void* expect_ptr : expected_ptrs) { bool is_freed = false; for (size_t j = 0; j < g_delete_array_call_cnt; j++) { if (g_deleted_ptr_records[j] == expect_ptr) { is_freed = true; break; } } ASSERT_TRUE(is_freed) << "指针" << expect_ptr << "未调用delete[]释放"; } }
注意事项
- 重写
operator delete[]后必须在内部调用free执行真正的内存释放,否则测试会出现内存泄漏甚至崩溃 - 多个测试用例运行时,必须在每个用例的开头重置计数和记录数组,避免用例间数据干扰
- 该方案对生产代码零侵入,是当前场景下成本最低、稳定性最高的测试方案
方案2:依赖注入+GMock校验(适合可修改代码签名的场景)
如果你可以修改freeMemory的函数签名,可以把内存操作抽象成接口做依赖注入,用GMock生成mock对象直接校验调用行为:
- 先定义内存操作抽象接口
struct MemoryOperator { virtual void deleteArray(void* ptr) = 0; virtual ~MemoryOperator() = default; };
- 生产环境用真实实现,测试用GMock生成Mock类
// 生产环境真实实现 struct RealMemoryOp : public MemoryOperator { void deleteArray(void* ptr) override { delete[] static_cast<char*>(ptr); } }; // 测试用Mock实现 struct MockMemoryOp : public MemoryOperator { MOCK_METHOD(void, deleteArray, (void* ptr), (override)); };
- 修改
freeMemory依赖该接口,测试时直接设置期望调用次数即可
该方案侵入性较强,需要修改原有函数的签名和调用逻辑,适合本身就做了分层解耦的代码库使用。
不要尝试直接对全局delete运算符打桩,C++标准不支持对全局运算符函数直接做动态mock,重写计数的方案是行业内通用的验证手段。
内容的提问来源于stack exchange,提问作者sattva_venu
相关产品推荐
相关产品推荐

