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

如何在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对象直接校验调用行为:

  1. 先定义内存操作抽象接口
struct MemoryOperator {
    virtual void deleteArray(void* ptr) = 0;
    virtual ~MemoryOperator() = default;
};
  1. 生产环境用真实实现,测试用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));
};
  1. 修改freeMemory依赖该接口,测试时直接设置期望调用次数即可

该方案侵入性较强,需要修改原有函数的签名和调用逻辑,适合本身就做了分层解耦的代码库使用。


不要尝试直接对全局delete运算符打桩,C++标准不支持对全局运算符函数直接做动态mock,重写计数的方案是行业内通用的验证手段。

内容的提问来源于stack exchange,提问作者sattva_venu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 00:03:49