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

Cmocka使用问题:如何mock通过函数指针调用的外部函数

Cmocka模拟结构体函数指针调用的方案

因为你的代码中是通过结构体成员的函数指针发起调用,不是直接调用全局外部函数,所以不需要用-Wl,--wrap的链接劫持方案,直接绑定自定义mock函数到对应函数指针即可,配合Cmocka原生的参数校验、返回值预设能力完成测试,具体实现步骤如下:


步骤1:定义和目标函数签名完全匹配的mock函数

要保证mock函数的返回值、入参个数和类型和原init函数指针的定义完全一致,示例代码:

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>

// 假设原init函数指针的签名为 INT32 (*init)(dev_t *dev),mock函数签名要完全对齐
INT32 mock_dev_init(dev_t *dev)
{
    // 可选:校验传入的dev参数是否符合测试预期
    check_expected(dev);
    // 返回测试用例中预设的mock返回值
    return mock_type(INT32);
}

步骤2:编写测试用例,绑定mock函数到结构体的函数指针

在测试用例中构造被测shell实例依赖的dev、ops结构体,将mock函数赋值给ops->init指针,再预设测试参数和返回值即可执行测试,以下是测试初始化失败场景的示例:

static void test_shellInit_dev_init_fail(void **state)
{
    // 构造测试所需的各结构体实例
    shell_t test_shell = {0};
    dev_t test_dev = {0};
    // 绑定mock函数到init函数指针
    dev_ops_t test_ops = {
        .init = mock_dev_init
    };

    // 组装指针关系,和被测代码的访问链路保持一致
    test_shell.dev = &test_dev;
    test_dev.ops = &test_ops;

    // 预设mock函数的入参预期和返回值
    expect_value(mock_dev_init, dev, &test_dev);
    will_return(mock_dev_init, ZKOS_FAILURE); // 模拟初始化失败场景

    // 调用被测函数
    INT32 ret = shellInit(&test_shell);

    // 校验结果是否符合预期
    assert_int_equal(ret, ZKOS_FAILURE);
}

其他测试场景扩展

  • 测试init指针为空的分支:直接将test_ops.init赋值为NULL即可,无需绑定mock函数,校验shellInit返回ZKOS_SUCCESS
  • 测试初始化成功的场景:把will_return的返回值改为ZKOS_SUCCESS,校验返回值为成功即可
  • 多次调用同一个mock函数的场景:多次调用will_return压入多个返回值,mock函数会按调用顺序依次取出返回

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 23:06:04