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

GMock测试Libcurl单元测试报EXPECT_CALL未调用跨版本异常

GMock测试C实现curl接口Mock失效问题排查方案

核心根因

  • Mock对象方法未被实际调用:EXPECT_CALL绑定的是CurlMocker类实例的成员方法,测试用例中直接调用全局真实curl_fetch_urlC函数,从未触发Mock对象方法,必然报「期望调用1次,实际0次」错误。
  • Mock方法签名不匹配:CurlMocker中定义的curl_fetch_url第一个参数为void*,且错误使用MOCK_CONST_METHOD3添加const修饰,与真实C函数签名不一致,CMock无法自动完成桩替换。
  • 测试用例参数错误:第二个用例调用curl_fetch_url时误将mock对象作为第一个参数传入,不符合函数CURL*类型的入参要求。
  • 跨版本差异原因:Oracle Linux 7默认编译链接选项宽松,Mock桩碰巧替换了真实函数符号;Oracle Linux 8默认开启PIE、符号可见性保护等安全编译选项,符号优先级规则变化导致桩注入失败,代码直接走真实libcurl逻辑,因此出现请求超时返回CURLE_OPERATION_TIMEDOUT(28)的现象。
  • 被测代码自带逻辑bug:presponse->payload = (char *)calloc(1, sizeof(presponse->payload));中分配内存大小写为sizeof(presponse->payload),实际计算的是char*指针长度(64位系统下为8字节),并非payload实际存储长度,后续写入响应内容时会触发缓冲区溢出。

修复步骤

  1. 修正Mock方法定义,保证签名与真实C函数完全一致
    修改curl_mocker.h中Mock类代码:
    class CurlMocker : public CMockMocker<CurlMocker>
    {
    public:
        // 第一个参数类型对齐真实函数,去掉错误的const修饰,使用MOCK_METHOD3
        MOCK_METHOD3(curl_fetch_url, int(CURL*, const char*, response_t*));
    };
    
  2. 修正测试用例逻辑,正确使用CMock桩替换能力
    CMock会自动拦截全局C函数调用,不需要手动传入mock对象作为函数参数,也不需要真实初始化libcurl(避免发起真实网络请求)。
    空入参测试用例修正后:
    TEST(curl_rest_call, curl_fetch_url_1) {
    #if !defined(__MINGW32__)
        int expected_ret = NULL_POINTER;
        CurlMocker mock;
        EXPECT_CALL(mock, curl_fetch_url(nullptr, nullptr, nullptr))
            .WillOnce(Return(NULL_POINTER));
        // 直接调用全局C函数,CMock会自动路由到Mock方法
        int actual_ret = curl_fetch_url(nullptr, nullptr, nullptr); 
        ASSERT_EQ(actual_ret, expected_ret);
    #endif
    }
    
    正常URL请求测试用例修正后:
    TEST(curl_rest_call, curl_fetch_url_2) {
    #if !defined(__MINGW32__)
        int expected_ret = CURLE_OK;
        const char *url = "https://someurl.com/posts/1";
        response_t response{};
        response.payload = nullptr;
        response.size = 0;
    
        CurlMocker mock;
        // 入参匹配不要直接比对栈指针地址,用匹配器校验参数合法性
        EXPECT_CALL(mock, curl_fetch_url(testing::_, testing::StrEq(url), testing::_))
            .WillOnce(testing::Invoke([&](CURL* curl, const char* u, response_t* resp) -> int {
                // 模拟接口返回,填充测试用的响应数据
                resp->size = 2;
                resp->payload = (char*)calloc(3, 1);
                memcpy(resp->payload, "ok", 2);
                return CURLE_OK;
            }));
        // 禁止传入mock对象作为第一参数,Mock场景下不会真实调用curl逻辑,传任意CURL*类型值即可
        int actual_ret = curl_fetch_url((CURL*)0x1234, url, &response);
        ASSERT_EQ(actual_ret, expected_ret);
        ASSERT_STREQ(response.payload, "ok");
    
        free(response.payload);
    #endif
    }
    
  3. 适配Oracle Linux 8编译选项
    编译测试用例时添加如下链接选项,保证CMock可以正常替换全局函数符号:
    LDFLAGS += -Wl,--allow-multiple-definition -no-pie -rdynamic
    
  4. 修复被测代码内存分配bug
    将固定大小分配改为curl写回调函数中按实际接收长度动态扩容,避免缓冲区溢出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:06:20