如何配置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时代码无法编译,解引用后调用触发段错误。
问题根因
- Google Mock API使用错误:
SetArgPointee<N>(val)的逻辑是将第N个参数作为指针,把val写入该指针指向的内存。当前传入的第1个参数(下标从0开始计数,对应char*类型的contents)是业务代码初始化的nullptr,向空指针指向的内存写数据必然触发段错误。另外SetArgPointee<1>期望写入的是char类型值,所以必须对json_response解引用取首字符才能编译通过,这和预期修改指针指向的需求完全不匹配。 - 接口签名不满足需求:目标是修改调用方的
contents指针本身、让它指向json_response数组,但当前接口第二个参数是值传递的char*,函数内部对参数的修改只会作用在临时副本上,根本无法影响外部的contents变量。
修复方案
根据接口实际语义二选一即可:
方案1:接口语义为调用方传入缓冲区,函数写入内容(HTTP接口通用设计)
这是最常见的GET接口设计:调用方提前分配接收缓冲区,传入缓冲区指针和长度,函数把响应内容拷贝到缓冲区,同时通过size引用返回实际内容长度。不需要修改接口签名,只需要调整测试和调用代码:
- 业务调用侧传入有效缓冲区,不要传空指针:
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为实际内容长度 }
- 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*&:
- 修正接口和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));
- 业务侧代码无需修改,保持原有空指针初始化写法即可。
- 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
相关产品推荐
相关产品推荐

