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

C++中如何使用GoogleMock在mock函数中填充传入的结构体参数

GoogleMock填充accept预分配出参结构体的正确方法

问题本质

对int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);做mock时,直接使用SetArgPointee<1>(*sa)无法正确填充调用方预分配的sockaddr_storage结构体,核心原因有两点:

  • sa是通用struct sockaddr*类型,解引用赋值时只会拷贝sockaddr类型的长度(通常16字节),而sockaddr_in中存储端口、IP的字段位于该偏移之后,会被直接截断
  • 真实系统调用除了填充addr指向的内存,还会将addrlen指向的值修改为实际写入的地址长度,原写法未同步更新该出参,不符合真实调用逻辑

推荐实现方式

使用Invoke自定义动作,直接操作mock函数接收到的指针参数,完全模拟真实accept的出参行为,不会出现类型截断问题。

  1. 提前在测试用例中定义预设的对端地址:
// 构造预期返回的对端地址
struct sockaddr_in preset_client{};
preset_client.sin_family = AF_INET;
preset_client.sin_port = htons(50000);
inet_pton(AF_INET, "192.168.1.2", &preset_client.sin_addr);
const socklen_t preset_client_len = sizeof(preset_client);
  1. 编写EXPECT_CALL逻辑,在DoAll中通过Invoke完成内存拷贝和出参更新:
EXPECT_CALL(mocked_sys_socket, accept(listen_sock, _, NotNull()))
    .WillOnce(DoAll(
        Invoke([&](int, struct sockaddr* out_addr, socklen_t* out_addrlen) {
            // 向调用方预分配的内存拷贝完整的地址结构体
            memcpy(out_addr, &preset_client, preset_client_len);
            // 同步更新地址长度为实际写入值,和内核行为一致
            *out_addrlen = preset_client_len;
        }),
        Return(accept_sock)
    ));

简化写法(不推荐)

如果业务代码完全不读取accept返回后的addrlen值,也可以使用SetArrayArgument拷贝整块内存,不需要自定义lambda:

EXPECT_CALL(mocked_sys_socket, accept(listen_sock, _, Pointee(clientLen)))
    .WillOnce(DoAll(
        SetArrayArgument<1>(
            reinterpret_cast<const char*>(&preset_client),
            reinterpret_cast<const char*>(&preset_client) + preset_client_len
        ),
        Return(accept_sock)
    ));

该写法省略了addrlen的更新逻辑,和真实系统调用行为不一致,后续业务逻辑如果依赖addrlen的返回值会触发难以排查的测试问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:57:14