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

如何配置Google Mock调用mock方法时为初始null的指针赋值

Google Mock 调用mock方法触发段错误修复方案

问题场景

在使用Google Mock编写C++单元测试时,调用mock的http_get方法触发段错误,相关代码如下:

Mock类定义

namespace iobox::services
{
    class web_api_mock : public iweb_api
    {
    public:
        MOCK_METHOD(
                (bool), 
                http_get, 
                (const etl_normal_string &, char*, size_t&), 
                (override));
        MOCK_METHOD(
                (bool), 
                http_post, 
                (const etl_normal_string &, const char*), 
                (override));
    };
}

单元测试代码片段

etl_normal_string category("mdb");
const size_t size = 100;
char json_response[size] = "{\n"
    "\t\"mdb\": \n"
    "\t\t{ \"always_idle\": true, \"multi_vend\": false, \"default_available_funds\": 123 }\n"
    "}\n";

EXPECT_CALL(
    _web_api_mock, 
    http_get(category, _, _))
    .WillOnce(
        DoAll(
            SetArgPointee<1>(*json_response),
            Return(true)));

业务调用代码

char * contents = nullptr; // 初始指针为空
size_t size;

if (_web_api.http_get( // 调用mock方法时触发段错误
    category.c_str(),
    contents,
    size))
{
  // 后续逻辑
}

问题现象

段错误问题截图
预期效果是调用mock后让contents指针指向测试代码中定义的json字符串,但当前使用SetArgPointee<1>(*json_response)写法错误:不解引用json_response时代码无法编译,解引用后调用触发段错误。

问题根因

  1. Google Mock API使用错误:SetArgPointee<N>(val)的逻辑是将第N个参数作为指针,把val写入该指针指向的内存。当前传入的第1个参数(下标从0开始计数,对应char*类型的contents)是业务代码初始化的nullptr,向空指针指向的内存写数据必然触发段错误。另外SetArgPointee<1>期望写入的是char类型值,所以必须对json_response解引用取首字符才能编译通过,这和预期修改指针指向的需求完全不匹配。
  2. 接口签名不满足需求:目标是修改调用方的contents指针本身、让它指向json_response数组,但当前接口第二个参数是值传递的char*,函数内部对参数的修改只会作用在临时副本上,根本无法影响外部的contents变量。

修复方案

根据接口实际语义二选一即可:

方案1:接口语义为调用方传入缓冲区,函数写入内容(HTTP接口通用设计)

这是最常见的GET接口设计:调用方提前分配接收缓冲区,传入缓冲区指针和长度,函数把响应内容拷贝到缓冲区,同时通过size引用返回实际内容长度。不需要修改接口签名,只需要调整测试和调用代码:

  1. 业务调用侧传入有效缓冲区,不要传空指针:
const size_t BUF_SIZE = 100;
char contents[BUF_SIZE] = {0};
size_t size = BUF_SIZE; // 初始传入缓冲区总大小

if (_web_api.http_get(category.c_str(), contents, size))
{
  // contents即为接收的json内容,size为实际内容长度
}
  1. Mock配置调整为拷贝内容到缓冲区、设置正确长度:
#include <cstring>

EXPECT_CALL(_web_api_mock, http_get(category, _, _))
    .WillOnce(DoAll(
        // 将json_response内容(含字符串结束符)拷贝到参数1指向的缓冲区
        SetArrayArgument<1>(json_response, json_response + strlen(json_response) + 1),
        // 设置参数2(size引用)为实际内容长度
        SetArgReferee<2>(strlen(json_response)),
        Return(true)
    ));

方案2:接口语义为函数返回内部字符串指针,修改调用方指针指向

如果要保持现有业务侧char* contents = nullptr的写法,让函数直接修改指针指向,首先需要修正接口签名,把第二个参数从值传递char*改为指针引用char*&:

  1. 修正接口和Mock类的方法签名:
// iweb_api接口声明修改为
virtual bool http_get(const etl_normal_string&, char*&, size_t&) = 0;

// Mock类对应MOCK_METHOD修改为
MOCK_METHOD(
    (bool), 
    http_get, 
    (const etl_normal_string &, char*&, size_t&), 
    (override));
  1. 业务侧代码无需修改,保持原有空指针初始化写法即可。
  2. Mock配置调整为直接设置指针指向、赋值长度:
#include <cstring>

EXPECT_CALL(_web_api_mock, http_get(category, _, _))
    .WillOnce(DoAll(
        // 将参数1(char*&)直接指向json_response数组
        SetArgReferee<1>(json_response),
        // 设置参数2为字符串实际长度
        SetArgReferee<2>(strlen(json_response)),
        Return(true)
    ));

注意:该方案下要保证json_response的生命周期覆盖所有使用contents指针的逻辑,避免野指针。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 16:15:10